/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 | | #[cfg(feature = "tdg_dbg")] |
60 | | const TDCALL_TDG_DEBUG: u64 = 254; |
61 | | |
62 | | // TDCALL completion status code |
63 | | const TDCALL_STATUS_SUCCESS: u64 = 0; |
64 | | |
65 | | // leaf-specific completion status code |
66 | | pub const TDCALL_STATUS_PAGE_ALREADY_ACCEPTED: u64 = 0x00000B0A00000000; |
67 | | pub const TDCALL_STATUS_PAGE_SIZE_MISMATCH: u64 = 0xC0000B0B00000001; |
68 | | |
69 | | cfg_if::cfg_if! { |
70 | | if #[cfg(not(feature = "no-tdvmcall"))] { |
71 | | // GTDG.VP.VMCALL leaf sub-function numbers |
72 | | const TDVMCALL_CPUID: u64 = 0x0000a; |
73 | | const TDVMCALL_HALT: u64 = 0x0000c; |
74 | | const TDVMCALL_IO: u64 = 0x0001e; |
75 | | const TDVMCALL_RDMSR: u64 = 0x0001f; |
76 | | const TDVMCALL_WRMSR: u64 = 0x00020; |
77 | | const TDVMCALL_MMIO: u64 = 0x00030; |
78 | | const TDVMCALL_MAPGPA: u64 = 0x10001; |
79 | | const TDVMCALL_GETQUOTE: u64 = 0x10002; |
80 | | const TDVMCALL_SETUPEVENTNOTIFY: u64 = 0x10004; |
81 | | const TDVMCALL_SERVICE: u64 = 0x10005; |
82 | | const TDVMCALL_MIGTD: u64 = 0x10006; |
83 | | |
84 | | // TDVMCALL completion status code |
85 | | const TDVMCALL_STATUS_SUCCESS: u64 = 0; |
86 | | const TDVMCALL_STATUS_RETRY: u64 = 1; |
87 | | |
88 | | // TDVMCALL<MigTD> leaf function numbers |
89 | | const TDVMCALL_MIGTD_WAITFORREQUEST: u16 = 1; |
90 | | const TDVMCALL_MIGTD_REPORTSTATUS: u16 = 2; |
91 | | const TDVMCALL_MIGTD_SEND: u16= 3; |
92 | | const TDVMCALL_MIGTD_RECEIVE: u16 = 4; |
93 | | } |
94 | | } |
95 | | |
96 | | // A public wrapper for use of asm_td_vmcall, this function takes a mutable reference of a |
97 | | // TdcallArgs structure to ensure the input is valid |
98 | | // |
99 | | // ## TDVMCALL ABI |
100 | | // Defined in GHCI Spec section 'TDCALL [TDG.VP.VMCALL] leaf' |
101 | | // |
102 | | // ### Input Operands: |
103 | | // * RAX - TDCALL instruction leaf number (0 - TDG.VP.VMCALL) |
104 | | // * RCX - A bitmap that controls which part of guest TD GPR is exposed to VMM. |
105 | | // * R10 - Set to 0 indicates leaf-function used in R11 is defined in standard GHCI Spec. |
106 | | // * R11 - TDG.VP.VMCALL sub-function is R10 is zero |
107 | | // * RBX, RBP, RDI, RSI, R8-R10, R12-R15 - Used to pass values to VMM in sub-functions. |
108 | | // |
109 | | // ### Output Operands: |
110 | | // * RAX - TDCALL instruction return code, always return Success(0). |
111 | | // * R10 - TDG.VP.VMCALL sub-function return value |
112 | | // * R11 - Correspond to each TDG.VP.VMCALL. |
113 | | // * R8-R9, R12-R15, RBX, RBP, RDI, RSI - Correspond to each TDG.VP.VMCALL sub-function. |
114 | | // |
115 | | #[cfg(not(feature = "no-tdvmcall"))] |
116 | 0 | pub fn td_vmcall(args: &mut TdVmcallArgs) -> u64 { |
117 | 0 | unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, 0) } |
118 | 0 | } |
119 | | |
120 | | // An extended public wrapper for use of asm_td_vmcall. |
121 | | // |
122 | | // `do_sti` is a flag used to determine whether to execute `sti` instruction before `tdcall` |
123 | | #[cfg(not(feature = "no-tdvmcall"))] |
124 | 0 | pub fn td_vmcall_ex(args: &mut TdVmcallArgs, do_sti: bool) -> u64 { |
125 | 0 | unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, do_sti as u64) } |
126 | 0 | } |
127 | | |
128 | | // An extended public wrapper for use of asm_td_vmcall_ex. |
129 | | // |
130 | | // `do_sti` is a flag used to determine whether to execute `sti` instruction before `tdcall` |
131 | | #[cfg(not(feature = "no-tdvmcall"))] |
132 | 0 | pub fn td_vmcall_ex2(args: &mut TdVmcallArgsEx, do_sti: bool) -> u64 { |
133 | 0 | unsafe { asm::asm_td_vmcall_ex(args as *mut TdVmcallArgsEx as *mut c_void, do_sti as u64) } |
134 | 0 | } |
135 | | |
136 | | // Wrapper for use of asm_td_call, this function takes a mutable reference of a |
137 | | // TdVmcallArgs structure to ensure the input is valid |
138 | | // |
139 | | // ## TDCALL ABI |
140 | | // Defined in TDX Module 1.0 Spec section 'TDCALL Instruction (Common)' |
141 | | // |
142 | | // ### Input Operands: |
143 | | // * RAX - Leaf and version numbers. |
144 | | // * Other - Used by leaf functions as input values. |
145 | | // |
146 | | // ### Output Operands: |
147 | | // * RAX - Instruction return code. |
148 | | // * Other - Used by leaf functions as output values. |
149 | | // |
150 | 0 | pub fn td_call(args: &mut TdcallArgs) -> u64 { |
151 | 0 | unsafe { asm::asm_td_call(args as *mut TdcallArgs as *mut c_void) } |
152 | 0 | } |
153 | | |
154 | | // Used to pass the values of input/output register when performing TDVMCALL |
155 | | // instruction |
156 | | #[repr(C)] |
157 | | #[derive(Default)] |
158 | | pub struct TdcallArgs { |
159 | | pub rax: u64, |
160 | | pub rcx: u64, |
161 | | pub rdx: u64, |
162 | | pub r8: u64, |
163 | | pub r9: u64, |
164 | | pub r10: u64, |
165 | | pub r11: u64, |
166 | | pub r12: u64, |
167 | | pub r13: u64, |
168 | | pub r14: u64, |
169 | | } |
170 | | |
171 | | // Used to pass the values of input/output register when performing TDVMCALL |
172 | | // instruction |
173 | | #[cfg(not(feature = "no-tdvmcall"))] |
174 | | #[repr(C)] |
175 | | #[derive(Default)] |
176 | | pub struct TdVmcallArgs { |
177 | | // Input: Always 0 for (standard VMCALL) |
178 | | // Output: Sub-function |
179 | | pub r10: u64, |
180 | | pub r11: u64, |
181 | | pub r12: u64, |
182 | | pub r13: u64, |
183 | | pub r14: u64, |
184 | | pub r15: u64, |
185 | | } |
186 | | |
187 | | // Used to pass the values of input/output register when performing TDVMCALL |
188 | | // instruction |
189 | | #[cfg(not(feature = "no-tdvmcall"))] |
190 | | #[repr(C)] |
191 | | #[derive(Default)] |
192 | | pub struct TdVmcallArgsEx { |
193 | | // Input: Always 0 for (standard VMCALL) |
194 | | // Output: Sub-function |
195 | | pub rdx: u64, |
196 | | pub rbx: u64, |
197 | | pub rsi: u64, |
198 | | pub rdi: u64, |
199 | | pub r8: u64, |
200 | | pub r9: u64, |
201 | | pub r10: u64, |
202 | | pub r11: u64, |
203 | | pub r12: u64, |
204 | | pub r13: u64, |
205 | | pub r14: u64, |
206 | | pub r15: u64, |
207 | | } |
208 | | |
209 | | /// TDCALL instruction return error code |
210 | | /// |
211 | | /// Refer to Intel TDX Module 1.0 Specifiction section 'TDCALL Instruction (Common)' |
212 | | #[derive(Debug, PartialEq)] |
213 | | pub enum TdCallError { |
214 | | // Invalid parameters |
215 | | TdxExitInvalidParameters, |
216 | | |
217 | | // The operand is busy (e.g., it is locked in Exclusive mode) |
218 | | TdxExitReasonOperandBusy(u32), |
219 | | |
220 | | // Operand is invalid (e.g., illegal leaf number) |
221 | | TdxExitReasonOperandInvalid(u32), |
222 | | |
223 | | // Error code defined by individual leaf function |
224 | | LeafSpecific(u64), |
225 | | } |
226 | | |
227 | | // TDCALL Completion Status Codes (Returned in RAX) Definition |
228 | | impl From<u64> for TdCallError { |
229 | 0 | fn from(val: u64) -> Self { |
230 | 0 | match val >> 32 { |
231 | 0 | 0x8000_0200 => Self::TdxExitReasonOperandBusy(val as u32), |
232 | 0 | 0xC000_0100 => Self::TdxExitReasonOperandInvalid(val as u32), |
233 | 0 | _ => Self::LeafSpecific(val), |
234 | | } |
235 | 0 | } |
236 | | } |
237 | | |
238 | | /// TDVMCALL sub-function return error code |
239 | | /// |
240 | | /// Refer to Guest-Host-Communication-Interface(GHCI) for Intel TDX |
241 | | /// table 'TDCALL[TDG.VP.VMCALL]- Sub-function Completion-Status Codes' |
242 | | #[cfg(not(feature = "no-tdvmcall"))] |
243 | | #[derive(Debug, PartialEq)] |
244 | | pub enum TdVmcallError { |
245 | | // TDCALL[TDG.VP.VMCALL] sub-function invocation must be retried |
246 | | VmcallRetry, |
247 | | |
248 | | // Invalid operand to TDG.VP.VMCALL sub-function |
249 | | VmcallOperandInvalid, |
250 | | |
251 | | // GPA already mapped |
252 | | VmcallGpaInuse, |
253 | | |
254 | | // Operand (address) alignment error |
255 | | VmcallAlignError, |
256 | | |
257 | | Other, |
258 | | } |
259 | | |
260 | | #[cfg(not(feature = "no-tdvmcall"))] |
261 | | impl From<u64> for TdVmcallError { |
262 | 0 | fn from(val: u64) -> Self { |
263 | 0 | match val { |
264 | 0 | 0x1 => TdVmcallError::VmcallRetry, |
265 | 0 | 0x8000_0000_0000_0000 => TdVmcallError::VmcallOperandInvalid, |
266 | 0 | 0x8000_0000_0000_0001 => TdVmcallError::VmcallGpaInuse, |
267 | 0 | 0x8000_0000_0000_0002 => TdVmcallError::VmcallAlignError, |
268 | 0 | _ => TdVmcallError::Other, |
269 | | } |
270 | 0 | } |
271 | | } |