x86defs/
tdx.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Intel TDX specific definitions.
5
6use crate::vmx;
7use bitfield_struct::bitfield;
8use open_enum::open_enum;
9use zerocopy::FromBytes;
10use zerocopy::Immutable;
11use zerocopy::IntoBytes;
12use zerocopy::KnownLayout;
13
14pub const TDX_SHARED_GPA_BOUNDARY_BITS: u8 = 47;
15pub const TDX_SHARED_GPA_BOUNDARY_ADDRESS_BIT: u64 = 1 << TDX_SHARED_GPA_BOUNDARY_BITS;
16pub const RESET_VECTOR_PAGE: u64 = 0xfffff000;
17
18open_enum! {
19    /// TDCALL instruction leafs that are passed into the tdcall instruction
20    /// in eax.
21    pub enum TdCallLeaf: u64 {
22        VP_VMCALL = 0,
23        VP_INFO = 1,
24        MR_RTMR_EXTEND = 2,
25        VP_VEINFO_GET = 3,
26        MR_REPORT = 4,
27        VP_CPUIDVE_SET = 5,
28        MEM_PAGE_ACCEPT = 6,
29        VM_RD = 7,
30        VM_WR = 8,
31        VP_RD = 9,
32        VP_WR = 10,
33        MEM_PAGE_ATTR_RD = 23,
34        MEM_PAGE_ATTR_WR = 24,
35        VP_ENTER = 25,
36        VP_INVGLA = 27,
37    }
38}
39
40/// Level used in various TDG.MEM.PAGE calls for GPA_MAPPING types.
41#[repr(u8)]
42#[derive(Clone, Copy, Debug, PartialEq, Eq)]
43pub enum TdgMemPageLevel {
44    Size4k = 0,
45    Size2Mb = 1,
46    Size1Gb = 2,
47}
48
49impl TdgMemPageLevel {
50    const fn from_bits(value: u64) -> Self {
51        match value {
52            0 => Self::Size4k,
53            1 => Self::Size2Mb,
54            2 => Self::Size1Gb,
55            _ => panic!("invalid TdgMemPageLevel value"),
56        }
57    }
58
59    const fn into_bits(self) -> u64 {
60        self as u64
61    }
62}
63
64/// Attributes for a single VM.
65#[bitfield(u16)]
66#[derive(PartialEq, Eq)]
67pub struct GpaVmAttributes {
68    pub read: bool,
69    pub write: bool,
70    pub kernel_execute: bool,
71    pub user_execute: bool,
72    #[bits(3)]
73    reserved: u8,
74    suppress_ve: bool,
75    #[bits(7)]
76    reserved2: u8,
77    pub valid: bool,
78}
79
80// Required impls for using within bitfield macros in other structs.
81impl GpaVmAttributes {
82    pub const FULL_ACCESS: Self = Self::new()
83        .with_read(true)
84        .with_write(true)
85        .with_kernel_execute(true)
86        .with_user_execute(true)
87        .with_valid(true);
88}
89
90/// Attributes mask used to set which bits are updated in TDG.MEM.PAGE.ATTR.WR.
91#[bitfield(u16)]
92pub struct GpaVmAttributesMask {
93    pub read: bool,
94    pub write: bool,
95    pub kernel_execute: bool,
96    pub user_execute: bool,
97    #[bits(3)]
98    reserved: u8,
99    pub suppress_ve: bool,
100    #[bits(7)]
101    reserved2: u8,
102    /// invalidate ept for this vm
103    pub inv_ept: bool,
104}
105
106impl GpaVmAttributesMask {
107    pub const ALL_CHANGED: Self = Self::new()
108        .with_read(true)
109        .with_write(true)
110        .with_kernel_execute(true)
111        .with_user_execute(true);
112}
113
114/// Corresponds to GPA_ATTR, which is used as input to TDG.MEM.PAGE.ATTR.WR and
115/// returned from TDG.MEM.PAGE.ATTR.RD.
116#[bitfield(u64)]
117#[derive(PartialEq, Eq)]
118pub struct TdgMemPageGpaAttr {
119    /// represents L1 vm aka VTL2
120    #[bits(16)]
121    pub l1: GpaVmAttributes,
122    /// Represetns L2 vm #1 which we use as VTL0
123    #[bits(16)]
124    pub l2_vm1: GpaVmAttributes,
125    /// Represents L2 vm #2 which we use as VTL1
126    #[bits(16)]
127    pub l2_vm2: GpaVmAttributes,
128    #[bits(16)]
129    pub l2_vm3: GpaVmAttributes,
130}
131
132#[bitfield(u64)]
133pub struct TdgMemPageAcceptRcx {
134    #[bits(3)]
135    pub level: TdgMemPageLevel,
136    #[bits(9)]
137    pub reserved: u64,
138    /// The page number for this accept call.
139    #[bits(40)]
140    pub gpa_page_number: u64,
141    #[bits(12)]
142    pub reserved2: u64,
143}
144
145#[bitfield(u64)]
146pub struct TdgMemPageAttrGpaMappingReadRcxResult {
147    #[bits(3)]
148    pub level: TdgMemPageLevel,
149    #[bits(9)]
150    pub reserved: u64,
151    /// The page number for this accept call.
152    #[bits(40)]
153    pub gpa_page_number: u64,
154    #[bits(10)]
155    pub reserved2: u64,
156    /// If this page's attributes are pending, meaning it will be applied when
157    /// the page is accepted.
158    #[bits(1)]
159    pub pending: u8,
160    #[bits(1)]
161    pub reserved3: u64,
162}
163
164/// RCX input to TDG.MEM.PAGE.ATTR.WR.
165#[bitfield(u64)]
166#[derive(PartialEq, Eq)]
167pub struct TdgMemPageAttrWriteRcx {
168    #[bits(3)]
169    pub level: TdgMemPageLevel,
170    #[bits(9)]
171    pub reserved: u64,
172    /// The page number for this write call.
173    #[bits(40)]
174    pub gpa_page_number: u64,
175    #[bits(12)]
176    pub reserved2: u64,
177}
178
179/// R8 input to TDG.MEM.PAGE.ATTR.WR.
180#[bitfield(u64)]
181pub struct TdgMemPageAttrWriteR8 {
182    #[bits(16)]
183    pub reserved: u64,
184    /// Corresponds to ATTR_MASK1
185    #[bits(16)]
186    pub l2_vm1: GpaVmAttributesMask,
187    /// Corresponds to ATTR_MASK2
188    #[bits(16)]
189    pub l2_vm2: GpaVmAttributesMask,
190    /// Corresponds to ATTR_MASK3
191    #[bits(16)]
192    pub l2_vm3: GpaVmAttributesMask,
193}
194
195/// The value specified in `r11` when making a TD vmcall, specified by `r10 =
196/// 0`.
197#[repr(u64)]
198pub enum TdVmCallSubFunction {
199    IoInstr = 0x1e,
200    RdMsr = 0x1f,
201    WrMsr = 0x20,
202    MapGpa = 0x10001,
203}
204
205open_enum! {
206    /// Result code for `tdcall` to the TDX module, returned in RAX.
207    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
208    pub enum TdCallResultCode: u32 {
209        SUCCESS = 0x00000000,
210        NON_RECOVERABLE_VCPU = 0x40000001,
211        NON_RECOVERABLE_TD = 0x60000002,
212        INTERRUPTED_RESUMABLE = 0x80000003,
213        INTERRUPTED_RESTARTABLE = 0x80000004,
214        NON_RECOVERABLE_TD_NON_ACCESSIBLE = 0x60000005,
215        INVALID_RESUMPTION = 0xC0000006,
216        NON_RECOVERABLE_TD_WRONG_APIC_MODE = 0xE0000007,
217        CROSS_TD_FAULT = 0x80000008,
218        CROSS_TD_TRAP = 0x90000009,
219        NON_RECOVERABLE_TD_CORRUPTED_MD = 0x6000000A,
220        OPERAND_INVALID = 0xC0000100,
221        OPERAND_ADDR_RANGE_ERROR = 0xC0000101,
222        OPERAND_BUSY = 0x80000200,
223        PREVIOUS_TLB_EPOCH_BUSY = 0x80000201,
224        SYS_BUSY = 0x80000202,
225        RND_NO_ENTROPY = 0x80000203,
226        OPERAND_BUSY_HOST_PRIORITY = 0x80000204,
227        HOST_PRIORITY_BUSY_TIMEOUT = 0x90000205,
228        PAGE_METADATA_INCORRECT = 0xC0000300,
229        PAGE_ALREADY_FREE = 0x00000301,
230        PAGE_NOT_OWNED_BY_TD = 0xC0000302,
231        PAGE_NOT_FREE = 0xC0000303,
232        TD_ASSOCIATED_PAGES_EXIST = 0xC0000400,
233        SYS_INIT_NOT_PENDING = 0xC0000500,
234        SYS_LP_INIT_NOT_DONE = 0xC0000502,
235        SYS_LP_INIT_DONE = 0xC0000503,
236        SYS_NOT_READY = 0xC0000505,
237        SYS_SHUTDOWN = 0xC0000506,
238        SYS_KEY_CONFIG_NOT_PENDING = 0xC0000507,
239        SYS_STATE_INCORRECT = 0xC0000508,
240        SYS_INVALID_HANDOFF = 0xC0000509,
241        SYS_INCOMPATIBLE_SIGSTRUCT = 0xC000050A,
242        SYS_LP_INIT_NOT_PENDING = 0xC000050B,
243        SYS_CONFIG_NOT_PENDING = 0xC000050C,
244        INCOMPATIBLE_SEAM_CAPABILITIES = 0xC000050D,
245        TD_FATAL = 0xE0000604,
246        TD_NON_DEBUG = 0xC0000605,
247        TDCS_NOT_ALLOCATED = 0xC0000606,
248        LIFECYCLE_STATE_INCORRECT = 0xC0000607,
249        OP_STATE_INCORRECT = 0xC0000608,
250        NO_VCPUS = 0xC0000609,
251        TDCX_NUM_INCORRECT = 0xC0000610,
252        VCPU_STATE_INCORRECT = 0xC0000700,
253        VCPU_ASSOCIATED = 0x80000701,
254        VCPU_NOT_ASSOCIATED = 0x80000702,
255        NO_VALID_VE_INFO = 0xC0000704,
256        MAX_VCPUS_EXCEEDED = 0xC0000705,
257        TSC_ROLLBACK = 0xC0000706,
258        TD_VMCS_FIELD_NOT_INITIALIZED = 0xC0000730,
259        MCS_FIELD_ERROR = 0xC0000731,
260        KEY_GENERATION_FAILED = 0x80000800,
261        TD_KEYS_NOT_CONFIGURED = 0x80000810,
262        KEY_STATE_INCORRECT = 0xC0000811,
263        KEY_CONFIGURED = 0x00000815,
264        WBCACHE_NOT_COMPLETE = 0x80000817,
265        HKID_NOT_FREE = 0xC0000820,
266        NO_HKID_READY_TO_WBCACHE = 0x00000821,
267        WBCACHE_RESUME_ERROR = 0xC0000823,
268        FLUSHVP_NOT_DONE = 0x80000824,
269        NUM_ACTIVATED_HKIDS_NOT_SUPPORTED = 0xC0000825,
270        INCORRECT_CPUID_VALUE = 0xC0000900,
271        LIMIT_CPUID_MAXVAL_SET = 0xC0000901,
272        INCONSISTENT_CPUID_FIELD = 0xC0000902,
273        CPUID_MAX_SUBLEAVES_UNRECOGNIZED = 0xC0000903,
274        CPUID_LEAF_1F_FORMAT_UNRECOGNIZED = 0xC0000904,
275        INVALID_WBINVD_SCOPE = 0xC0000905,
276        INVALID_PKG_ID = 0xC0000906,
277        ENABLE_MONITOR_FSM_NOT_SET = 0xC0000907,
278        CPUID_LEAF_NOT_SUPPORTED = 0xC0000908,
279        SMRR_NOT_LOCKED = 0xC0000910,
280        INVALID_SMRR_CONFIGURATION = 0xC0000911,
281        SMRR_OVERLAPS_CMR = 0xC0000912,
282        SMRR_LOCK_NOT_SUPPORTED = 0xC0000913,
283        SMRR_NOT_SUPPORTED = 0xC0000914,
284        INCONSISTENT_MSR = 0xC0000920,
285        INCORRECT_MSR_VALUE = 0xC0000921,
286        SEAMREPORT_NOT_AVAILABLE = 0xC0000930,
287        SEAMDB_GETREF_NOT_AVAILABLE = 0xC0000931,
288        SEAMDB_REPORT_NOT_AVAILABLE = 0xC0000932,
289        SEAMVERIFYREPORT_NOT_AVAILABLE = 0xC0000933,
290        INVALID_TDMR = 0xC0000A00,
291        NON_ORDERED_TDMR = 0xC0000A01,
292        TDMR_OUTSIDE_CMRS = 0xC0000A02,
293        TDMR_ALREADY_INITIALIZED = 0x00000A03,
294        INVALID_PAMT = 0xC0000A10,
295        PAMT_OUTSIDE_CMRS = 0xC0000A11,
296        PAMT_OVERLAP = 0xC0000A12,
297        INVALID_RESERVED_IN_TDMR = 0xC0000A20,
298        NON_ORDERED_RESERVED_IN_TDMR = 0xC0000A21,
299        CMR_LIST_INVALID = 0xC0000A22,
300        EPT_WALK_FAILED = 0xC0000B00,
301        EPT_ENTRY_FREE = 0xC0000B01,
302        EPT_ENTRY_NOT_FREE = 0xC0000B02,
303        EPT_ENTRY_NOT_PRESENT = 0xC0000B03,
304        EPT_ENTRY_NOT_LEAF = 0xC0000B04,
305        EPT_ENTRY_LEAF = 0xC0000B05,
306        GPA_RANGE_NOT_BLOCKED = 0xC0000B06,
307        GPA_RANGE_ALREADY_BLOCKED = 0x00000B07,
308        TLB_TRACKING_NOT_DONE = 0xC0000B08,
309        EPT_INVALID_PROMOTE_CONDITIONS = 0xC0000B09,
310        PAGE_ALREADY_ACCEPTED = 0x00000B0A,
311        PAGE_SIZE_MISMATCH = 0xC0000B0B,
312        GPA_RANGE_BLOCKED = 0xC0000B0C,
313        EPT_ENTRY_STATE_INCORRECT = 0xC0000B0D,
314        EPT_PAGE_NOT_FREE = 0xC0000B0E,
315        L2_SEPT_WALK_FAILED = 0xC0000B0F,
316        L2_SEPT_ENTRY_NOT_FREE = 0xC0000B10,
317        PAGE_ATTR_INVALID = 0xC0000B11,
318        L2_SEPT_PAGE_NOT_PROVIDED = 0xC0000B12,
319        METADATA_FIELD_ID_INCORRECT = 0xC0000C00,
320        METADATA_FIELD_NOT_WRITABLE = 0xC0000C01,
321        METADATA_FIELD_NOT_READABLE = 0xC0000C02,
322        METADATA_FIELD_VALUE_NOT_VALID = 0xC0000C03,
323        METADATA_LIST_OVERFLOW = 0xC0000C04,
324        INVALID_METADATA_LIST_HEADER = 0xC0000C05,
325        REQUIRED_METADATA_FIELD_MISSING = 0xC0000C06,
326        METADATA_ELEMENT_SIZE_INCORRECT = 0xC0000C07,
327        METADATA_LAST_ELEMENT_INCORRECT = 0xC0000C08,
328        METADATA_FIELD_CURRENTLY_NOT_WRITABLE = 0xC0000C09,
329        METADATA_WR_MASK_NOT_VALID = 0xC0000C0A,
330        METADATA_FIRST_FIELD_ID_IN_CONTEXT = 0x00000C0B,
331        METADATA_FIELD_SKIP = 0x00000C0C,
332        SERVTD_ALREADY_BOUND_FOR_TYPE = 0xC0000D00,
333        SERVTD_TYPE_MISMATCH = 0xC0000D01,
334        SERVTD_ATTR_MISMATCH = 0xC0000D02,
335        SERVTD_INFO_HASH_MISMATCH = 0xC0000D03,
336        SERVTD_UUID_MISMATCH = 0xC0000D04,
337        SERVTD_NOT_BOUND = 0xC0000D05,
338        SERVTD_BOUND = 0xC0000D06,
339        TARGET_UUID_MISMATCH = 0xC0000D07,
340        TARGET_UUID_UPDATED = 0xC0000D08,
341        INVALID_MBMD = 0xC0000E00,
342        INCORRECT_MBMD_MAC = 0xC0000E01,
343        NOT_WRITE_BLOCKED = 0xC0000E02,
344        ALREADY_WRITE_BLOCKED = 0x00000E03,
345        NOT_EXPORTED = 0xC0000E04,
346        MIGRATION_STREAM_STATE_INCORRECT = 0xC0000E05,
347        MAX_MIGS_NUM_EXCEEDED = 0xC0000E06,
348        EXPORTED_DIRTY_PAGES_REMAIN = 0xC0000E07,
349        MIGRATION_DECRYPTION_KEY_NOT_SET = 0xC0000E08,
350        TD_NOT_MIGRATABLE = 0xC0000E09,
351        PREVIOUS_EXPORT_CLEANUP_INCOMPLETE = 0xC0000E0A,
352        NUM_MIGS_HIGHER_THAN_CREATED = 0xC0000E0B,
353        IMPORT_MISMATCH = 0xC0000E0C,
354        MIGRATION_EPOCH_OVERFLOW = 0xC0000E0D,
355        MAX_EXPORTS_EXCEEDED = 0xC0000E0E,
356        INVALID_PAGE_MAC = 0xC0000E0F,
357        MIGRATED_IN_CURRENT_EPOCH = 0xC0000E10,
358        DISALLOWED_IMPORT_OVER_REMOVED = 0xC0000E11,
359        SOME_VCPUS_NOT_MIGRATED = 0xC0000E12,
360        ALL_VCPUS_IMPORTED = 0xC0000E13,
361        MIN_MIGS_NOT_CREATED = 0xC0000E14,
362        VCPU_ALREADY_EXPORTED = 0xC0000E15,
363        INVALID_MIGRATION_DECRYPTION_KEY = 0xC0000E16,
364        INVALID_CPUSVN = 0xC0001000,
365        INVALID_REPORTMACSTRUCT = 0xC0001001,
366        L2_EXIT_HOST_ROUTED_ASYNC = 0x00001100,
367        L2_EXIT_HOST_ROUTED_TDVMCALL = 0x00001101,
368        L2_EXIT_PENDING_INTERRUPT = 0x00001102,
369        PENDING_INTERRUPT = 0x00001120,
370        TD_EXIT_BEFORE_L2_ENTRY = 0x00001140,
371        TD_EXIT_ON_L2_VM_EXIT = 0x00001141,
372        TD_EXIT_ON_L2_TO_L1 = 0x00001142,
373        GLA_NOT_CANONICAL = 0xC0001160,
374    }
375}
376
377impl TdCallResultCode {
378    const fn from_bits(value: u64) -> Self {
379        Self(value as u32)
380    }
381
382    const fn into_bits(self) -> u64 {
383        self.0 as u64
384    }
385}
386
387/// The result returned by a tdcall instruction in rax.
388#[bitfield(u64)]
389pub struct TdCallResult {
390    pub details: u32,
391    #[bits(32)]
392    pub code: TdCallResultCode,
393}
394
395open_enum! {
396    /// The result returned by a tdg.vm.call in r10.
397    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
398    pub enum TdVmCallR10Result: u64 {
399        SUCCESS = 0,
400        RETRY = 1,
401        OPERAND_INVALID = 0x80000000_00000000,
402        GPA_INUSE = 0x80000000_00000001,
403        ALIGN_ERROR = 0x80000000_00000002,
404    }
405}
406
407/// Field size for [`TdxExtendedFieldCode`].
408#[repr(u64)]
409#[derive(Debug)]
410pub enum FieldSize {
411    Invalid = 0,
412    Size16Bit = 1,
413    Size32Bit = 2,
414    Size64Bit = 3,
415}
416
417impl FieldSize {
418    const fn from_bits(value: u64) -> Self {
419        match value {
420            0 => FieldSize::Invalid,
421            1 => FieldSize::Size16Bit,
422            2 => FieldSize::Size32Bit,
423            3 => FieldSize::Size64Bit,
424            _ => panic!("Invalid field size"),
425        }
426    }
427
428    const fn into_bits(self) -> u64 {
429        self as u64
430    }
431}
432
433open_enum! {
434    pub enum TdVpsClassCode: u8 {
435        TD_VMCS = 0,
436        VAPIC = 1,
437        VE_INFO = 2,
438        GUEST_GPR_STATE = 16,
439        GUEST_STATE = 17,
440        GUEST_EXT_STATE = 18,
441        GUEST_MSR_STATE = 19,
442        MANAGEMENT = 32,
443        CPUID_CONTROL = 33,
444        EPT_VIOLATION_LOG = 34,
445        VMCS_1 = 36,
446        MSR_BITMAPS_1 = 37,
447        MSR_BITMAPS_SHADOW_1 = 38,
448        VMCS_2 = 44,
449        MSR_BITMAPS_2 = 45,
450        MSR_BITMAPS_SHADOW_2 = 46,
451        VMCS_3 = 52,
452    }
453}
454
455open_enum! {
456    pub enum TdxContextCode: u8 {
457        PLATFORM = 0,
458        TD = 1,
459        TD_VCPU = 2,
460    }
461}
462
463impl TdxContextCode {
464    const fn from_bits(value: u64) -> Self {
465        Self(value as u8)
466    }
467    const fn into_bits(self) -> u64 {
468        self.0 as u64
469    }
470}
471
472pub const TDX_FIELD_CODE_L2_CTLS_VM1: TdxExtendedFieldCode =
473    TdxExtendedFieldCode(0xA020000300000051);
474pub const TDX_FIELD_CODE_L2_CTLS_VM2: TdxExtendedFieldCode =
475    TdxExtendedFieldCode(0xA020000300000051);
476
477/// Extended field code for TDG.VP.WR and TDG.VP.RD
478#[bitfield(u64)]
479pub struct TdxExtendedFieldCode {
480    #[bits(24)]
481    pub field_code: u32,
482    #[bits(8)]
483    _reserved0: u64,
484    #[bits(2)]
485    pub field_size: FieldSize,
486    #[bits(4)]
487    pub last_element: u8,
488    #[bits(9)]
489    pub last_field: u16,
490    #[bits(3)]
491    _reserved1: u64,
492    pub increment_size: bool,
493    pub write_mask_valid: bool,
494    #[bits(3)]
495    pub context_code: TdxContextCode,
496    #[bits(1)]
497    _reserved2: u64,
498    #[bits(6)]
499    pub class_code: u8,
500    #[bits(1)]
501    _reserved3: u64,
502    pub non_arch: bool,
503}
504
505/// Instruction info returned in r11 for a TDG.VP.ENTER call.
506#[bitfield(u64)]
507pub struct TdxInstructionInfo {
508    pub info: u32,
509    pub length: u32,
510}
511
512#[bitfield(u64)]
513pub struct TdxL2Ctls {
514    pub enable_shared_ept: bool,
515    pub enable_tdvmcall: bool,
516    #[bits(62)]
517    pub reserved: u64,
518}
519
520#[bitfield(u64)]
521pub struct TdxVpEnterRaxResult {
522    /// The VMX exit code for VP.ENTER, if valid.
523    #[bits(32)]
524    pub vmx_exit: vmx::VmxExit,
525    /// The TDX specific exit code.
526    #[bits(32)]
527    pub tdx_exit: TdCallResultCode,
528}
529
530#[bitfield(u64)]
531pub struct TdxExtendedExitQualification {
532    #[bits(4)]
533    pub ty: TdxExtendedExitQualificationType,
534    #[bits(60)]
535    _reserved: u64,
536}
537
538open_enum! {
539    pub enum TdxExtendedExitQualificationType: u8 {
540        NONE = 0,
541        PENDING_EPT_VIOLATION = 6,
542    }
543}
544
545impl TdxExtendedExitQualificationType {
546    const fn from_bits(value: u64) -> Self {
547        Self(value as u8)
548    }
549
550    const fn into_bits(self) -> u64 {
551        self.0 as u64
552    }
553}
554
555/// The GPR list used for TDG.VP.ENTER. Specified in the TDX specification as
556/// L2_ENTER_GUEST_STATE.
557#[repr(C)]
558#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
559pub struct TdxL2EnterGuestState {
560    /// GPs in the usual order.
561    pub gps: [u64; 16],
562    pub rflags: u64,
563    pub rip: u64,
564    pub ssp: u64,
565    pub rvi: u8, // GUEST_INTERRUPT_STATUS lower bits
566    pub svi: u8, // GUEST_INTERRUPT_STATUS upper bits
567    pub reserved: [u8; 6],
568}
569
570pub enum TdxGp {}
571impl TdxGp {
572    pub const RAX: usize = 0;
573    pub const RCX: usize = 1;
574    pub const RDX: usize = 2;
575    pub const RBX: usize = 3;
576    pub const RSP: usize = 4;
577    pub const RBP: usize = 5;
578    pub const RSI: usize = 6;
579    pub const RDI: usize = 7;
580    pub const R8: usize = 8;
581    pub const R9: usize = 9;
582    pub const R10: usize = 10;
583    pub const R11: usize = 11;
584    pub const R12: usize = 12;
585    pub const R13: usize = 13;
586    pub const R14: usize = 14;
587    pub const R15: usize = 15;
588}
589
590#[bitfield(u64)]
591pub struct TdxGlaListInfo {
592    #[bits(9)]
593    pub first_entry: u64,
594    #[bits(3)]
595    _reserved_z0: u64,
596    #[bits(40)]
597    pub list_gpa: u64,
598    #[bits(10)]
599    pub num_entries: u64,
600    #[bits(2)]
601    _reserved_z1: u64,
602}
603
604#[bitfield(u64)]
605pub struct TdGlaVmAndFlags {
606    pub list: bool,
607    #[bits(51)]
608    _reserved_z0: u64,
609    #[bits(2)]
610    pub vm_index: u64,
611    #[bits(10)]
612    _reserved_z1: u64,
613}
614
615#[bitfield(u64)]
616#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
617pub struct TdxVmFlags {
618    #[bits(2)]
619    pub invd_translations: u8,
620
621    #[bits(50)]
622    _reserved: u64,
623
624    /// Starts at 1, not 0.
625    #[bits(2)]
626    pub vm_index: u8,
627
628    #[bits(10)]
629    _reserved_2: u64,
630}
631
632pub const TDX_VP_ENTER_INVD_INVEPT: u8 = 1;
633pub const TDX_VP_ENTER_INVD_INVVPID: u8 = 2;
634pub const TDX_VP_ENTER_INVD_INVVPID_NON_GLOBAL: u8 = 3;