tdx_tdcall/lib.rs
1// Copyright (c) 2020-2022 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
24extern crate alloc;
25use core::ffi::c_void;
26
27#[cfg(feature = "use_tdx_emulation")]
28pub const USE_TDX_EMULATION: bool = true;
29#[cfg(not(feature = "use_tdx_emulation"))]
30pub const USE_TDX_EMULATION: bool = false;
31
32pub mod asm;
33pub mod tdreport;
34pub mod tdx;
35
36// Guest-Side (TDCALL) interface functions leaf numbers
37const TDCALL_TDINFO: u64 = 1;
38const TDCALL_TDEXTENDRTMR: u64 = 2;
39const TDCALL_TDGETVEINFO: u64 = 3;
40const TDCALL_TDREPORT: u64 = 4;
41const TDCALL_TDACCEPTPAGE: u64 = 6;
42const TDCALL_VM_RD: u64 = 7;
43const TDCALL_VM_WR: u64 = 8;
44const TDCALL_VP_RD: u64 = 9;
45const TDCALL_VP_WR: u64 = 10;
46const TDCALL_SYS_RD: u64 = 11;
47const TDCALL_SERVTD_RD: u64 = 18;
48const TDCALL_SERVTD_WR: u64 = 20;
49const TDCALL_MEM_PAGE_ATTR_WR: u64 = 24;
50const TDCALL_VP_ENTER: u64 = 25;
51const TDCALL_VP_INVEPT: u64 = 26;
52const TDCALL_VP_INVVPID: u64 = 27;
53
54// GTDG.VP.VMCALL leaf sub-function numbers
55const TDVMCALL_CPUID: u64 = 0x0000a;
56const TDVMCALL_HALT: u64 = 0x0000c;
57const TDVMCALL_IO: u64 = 0x0001e;
58const TDVMCALL_RDMSR: u64 = 0x0001f;
59const TDVMCALL_WRMSR: u64 = 0x00020;
60const TDVMCALL_MMIO: u64 = 0x00030;
61const TDVMCALL_MAPGPA: u64 = 0x10001;
62const TDVMCALL_GETQUOTE: u64 = 0x10002;
63const TDVMCALL_SETUPEVENTNOTIFY: u64 = 0x10004;
64const TDVMCALL_SERVICE: u64 = 0x10005;
65
66// TDCALL completion status code
67const TDCALL_STATUS_SUCCESS: u64 = 0;
68
69// leaf-specific completion status code
70pub const TDCALL_STATUS_PAGE_ALREADY_ACCEPTED: u64 = 0x00000B0A00000000;
71pub const TDCALL_STATUS_PAGE_SIZE_MISMATCH: u64 = 0xC0000B0B00000001;
72
73// TDVMCALL completion status code
74const TDVMCALL_STATUS_SUCCESS: u64 = 0;
75const TDVMCALL_STATUS_RETRY: u64 = 1;
76
77// A public wrapper for use of asm_td_vmcall, this function takes a mutable reference of a
78// TdcallArgs structure to ensure the input is valid
79//
80// ## TDVMCALL ABI
81// Defined in GHCI Spec section 'TDCALL [TDG.VP.VMCALL] leaf'
82//
83// ### Input Operands:
84// * RAX - TDCALL instruction leaf number (0 - TDG.VP.VMCALL)
85// * RCX - A bitmap that controls which part of guest TD GPR is exposed to VMM.
86// * R10 - Set to 0 indicates leaf-function used in R11 is defined in standard GHCI Spec.
87// * R11 - TDG.VP.VMCALL sub-function is R10 is zero
88// * RBX, RBP, RDI, RSI, R8-R10, R12-R15 - Used to pass values to VMM in sub-functions.
89//
90// ### Output Operands:
91// * RAX - TDCALL instruction return code, always return Success(0).
92// * R10 - TDG.VP.VMCALL sub-function return value
93// * R11 - Correspond to each TDG.VP.VMCALL.
94// * R8-R9, R12-R15, RBX, RBP, RDI, RSI - Correspond to each TDG.VP.VMCALL sub-function.
95//
96pub fn td_vmcall(args: &mut TdVmcallArgs) -> u64 {
97 unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, 0) }
98}
99
100// An extended public wrapper for use of asm_td_vmcall.
101//
102// `do_sti` is a flag used to determine whether to execute `sti` instruction before `tdcall`
103pub fn td_vmcall_ex(args: &mut TdVmcallArgs, do_sti: bool) -> u64 {
104 unsafe { asm::asm_td_vmcall(args as *mut TdVmcallArgs as *mut c_void, do_sti as u64) }
105}
106
107// Wrapper for use of asm_td_call, this function takes a mutable reference of a
108// TdVmcallArgs structure to ensure the input is valid
109//
110// ## TDCALL ABI
111// Defined in TDX Module 1.0 Spec section 'TDCALL Instruction (Common)'
112//
113// ### Input Operands:
114// * RAX - Leaf and version numbers.
115// * Other - Used by leaf functions as input values.
116//
117// ### Output Operands:
118// * RAX - Instruction return code.
119// * Other - Used by leaf functions as output values.
120//
121pub fn td_call(args: &mut TdcallArgs) -> u64 {
122 unsafe { asm::asm_td_call(args as *mut TdcallArgs as *mut c_void) }
123}
124
125// Used to pass the values of input/output register when performing TDVMCALL
126// instruction
127#[repr(C)]
128#[derive(Default)]
129pub struct TdcallArgs {
130 pub rax: u64,
131 pub rcx: u64,
132 pub rdx: u64,
133 pub r8: u64,
134 pub r9: u64,
135 pub r10: u64,
136 pub r11: u64,
137 pub r12: u64,
138 pub r13: u64,
139}
140
141// Used to pass the values of input/output register when performing TDVMCALL
142// instruction
143#[repr(C)]
144#[derive(Default)]
145pub struct TdVmcallArgs {
146 // Input: Always 0 for (standard VMCALL)
147 // Output: Sub-function
148 pub r10: u64,
149 pub r11: u64,
150 pub r12: u64,
151 pub r13: u64,
152 pub r14: u64,
153 pub r15: u64,
154}
155
156/// TDCALL instruction return error code
157///
158/// Refer to Intel TDX Module 1.0 Specifiction section 'TDCALL Instruction (Common)'
159#[derive(Debug, PartialEq)]
160pub enum TdCallError {
161 // Invalid parameters
162 TdxExitInvalidParameters,
163
164 // The operand is busy (e.g., it is locked in Exclusive mode)
165 TdxExitReasonOperandBusy(u32),
166
167 // Operand is invalid (e.g., illegal leaf number)
168 TdxExitReasonOperandInvalid(u32),
169
170 // Error code defined by individual leaf function
171 LeafSpecific(u64),
172}
173
174// TDCALL Completion Status Codes (Returned in RAX) Definition
175impl From<u64> for TdCallError {
176 fn from(val: u64) -> Self {
177 match val >> 32 {
178 0x8000_0200 => Self::TdxExitReasonOperandBusy(val as u32),
179 0xC000_0100 => Self::TdxExitReasonOperandInvalid(val as u32),
180 _ => Self::LeafSpecific(val),
181 }
182 }
183}
184
185/// TDVMCALL sub-function return error code
186///
187/// Refer to Guest-Host-Communication-Interface(GHCI) for Intel TDX
188/// table 'TDCALL[TDG.VP.VMCALL]- Sub-function Completion-Status Codes'
189#[derive(Debug, PartialEq)]
190pub enum TdVmcallError {
191 // TDCALL[TDG.VP.VMCALL] sub-function invocation must be retried
192 VmcallRetry,
193
194 // Invalid operand to TDG.VP.VMCALL sub-function
195 VmcallOperandInvalid,
196
197 // GPA already mapped
198 VmcallGpaInuse,
199
200 // Operand (address) alignment error
201 VmcallAlignError,
202
203 Other,
204}
205
206impl From<u64> for TdVmcallError {
207 fn from(val: u64) -> Self {
208 match val {
209 0x1 => TdVmcallError::VmcallRetry,
210 0x8000_0000_0000_0000 => TdVmcallError::VmcallOperandInvalid,
211 0x8000_0000_0000_0001 => TdVmcallError::VmcallGpaInuse,
212 0x8000_0000_0000_0002 => TdVmcallError::VmcallAlignError,
213 _ => TdVmcallError::Other,
214 }
215 }
216}