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