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
18/// Size of the [`TdReport`].
19pub const TDX_REPORT_SIZE: usize = 0x400;
20
21/// Size of `report_data` member in [`ReportMac`].
22pub const TDX_REPORT_DATA_SIZE: usize = 64;
23
24open_enum! {
25    /// TDCALL instruction leafs that are passed into the tdcall instruction
26    /// in eax.
27    pub enum TdCallLeaf: u64 {
28        VP_VMCALL = 0,
29        VP_INFO = 1,
30        MR_RTMR_EXTEND = 2,
31        VP_VEINFO_GET = 3,
32        MR_REPORT = 4,
33        VP_CPUIDVE_SET = 5,
34        MEM_PAGE_ACCEPT = 6,
35        VM_RD = 7,
36        VM_WR = 8,
37        VP_RD = 9,
38        VP_WR = 10,
39        MEM_PAGE_ATTR_RD = 23,
40        MEM_PAGE_ATTR_WR = 24,
41        VP_ENTER = 25,
42        VP_INVGLA = 27,
43    }
44}
45
46/// Level used in various TDG.MEM.PAGE calls for GPA_MAPPING types.
47#[repr(u8)]
48#[derive(Clone, Copy, Debug, PartialEq, Eq)]
49pub enum TdgMemPageLevel {
50    Size4k = 0,
51    Size2Mb = 1,
52    Size1Gb = 2,
53}
54
55impl TdgMemPageLevel {
56    const fn from_bits(value: u64) -> Self {
57        match value {
58            0 => Self::Size4k,
59            1 => Self::Size2Mb,
60            2 => Self::Size1Gb,
61            _ => panic!("invalid TdgMemPageLevel value"),
62        }
63    }
64
65    const fn into_bits(self) -> u64 {
66        self as u64
67    }
68}
69
70/// Attributes for a single VM.
71#[bitfield(u16)]
72#[derive(PartialEq, Eq)]
73pub struct GpaVmAttributes {
74    pub read: bool,
75    pub write: bool,
76    pub kernel_execute: bool,
77    pub user_execute: bool,
78    #[bits(3)]
79    reserved: u8,
80    suppress_ve: bool,
81    #[bits(7)]
82    reserved2: u8,
83    pub valid: bool,
84}
85
86// Required impls for using within bitfield macros in other structs.
87impl GpaVmAttributes {
88    pub const FULL_ACCESS: Self = Self::new()
89        .with_read(true)
90        .with_write(true)
91        .with_kernel_execute(true)
92        .with_user_execute(true)
93        .with_valid(true);
94}
95
96/// Attributes mask used to set which bits are updated in TDG.MEM.PAGE.ATTR.WR.
97#[bitfield(u16)]
98pub struct GpaVmAttributesMask {
99    pub read: bool,
100    pub write: bool,
101    pub kernel_execute: bool,
102    pub user_execute: bool,
103    #[bits(3)]
104    reserved: u8,
105    pub suppress_ve: bool,
106    #[bits(7)]
107    reserved2: u8,
108    /// invalidate ept for this vm
109    pub inv_ept: bool,
110}
111
112impl GpaVmAttributesMask {
113    pub const ALL_CHANGED: Self = Self::new()
114        .with_read(true)
115        .with_write(true)
116        .with_kernel_execute(true)
117        .with_user_execute(true);
118}
119
120/// Corresponds to GPA_ATTR, which is used as input to TDG.MEM.PAGE.ATTR.WR and
121/// returned from TDG.MEM.PAGE.ATTR.RD.
122#[bitfield(u64)]
123#[derive(PartialEq, Eq)]
124pub struct TdgMemPageGpaAttr {
125    /// represents L1 vm aka VTL2
126    #[bits(16)]
127    pub l1: GpaVmAttributes,
128    /// Represetns L2 vm #1 which we use as VTL0
129    #[bits(16)]
130    pub l2_vm1: GpaVmAttributes,
131    /// Represents L2 vm #2 which we use as VTL1
132    #[bits(16)]
133    pub l2_vm2: GpaVmAttributes,
134    #[bits(16)]
135    pub l2_vm3: GpaVmAttributes,
136}
137
138#[bitfield(u64)]
139pub struct TdgMemPageAcceptRcx {
140    #[bits(3)]
141    pub level: TdgMemPageLevel,
142    #[bits(9)]
143    pub reserved: u64,
144    /// The page number for this accept call.
145    #[bits(40)]
146    pub gpa_page_number: u64,
147    #[bits(12)]
148    pub reserved2: u64,
149}
150
151#[bitfield(u64)]
152pub struct TdgMemPageAttrGpaMappingReadRcxResult {
153    #[bits(3)]
154    pub level: TdgMemPageLevel,
155    #[bits(9)]
156    pub reserved: u64,
157    /// The page number for this accept call.
158    #[bits(40)]
159    pub gpa_page_number: u64,
160    #[bits(10)]
161    pub reserved2: u64,
162    /// If this page's attributes are pending, meaning it will be applied when
163    /// the page is accepted.
164    #[bits(1)]
165    pub pending: u8,
166    #[bits(1)]
167    pub reserved3: u64,
168}
169
170/// RCX input to TDG.MEM.PAGE.ATTR.WR.
171#[bitfield(u64)]
172#[derive(PartialEq, Eq)]
173pub struct TdgMemPageAttrWriteRcx {
174    #[bits(3)]
175    pub level: TdgMemPageLevel,
176    #[bits(9)]
177    pub reserved: u64,
178    /// The page number for this write call.
179    #[bits(40)]
180    pub gpa_page_number: u64,
181    #[bits(12)]
182    pub reserved2: u64,
183}
184
185/// R8 input to TDG.MEM.PAGE.ATTR.WR.
186#[bitfield(u64)]
187pub struct TdgMemPageAttrWriteR8 {
188    #[bits(16)]
189    pub reserved: u64,
190    /// Corresponds to ATTR_MASK1
191    #[bits(16)]
192    pub l2_vm1: GpaVmAttributesMask,
193    /// Corresponds to ATTR_MASK2
194    #[bits(16)]
195    pub l2_vm2: GpaVmAttributesMask,
196    /// Corresponds to ATTR_MASK3
197    #[bits(16)]
198    pub l2_vm3: GpaVmAttributesMask,
199}
200
201/// The value specified in `r11` when making a TD vmcall, specified by `r10 =
202/// 0`.
203#[repr(u64)]
204pub enum TdVmCallSubFunction {
205    IoInstr = 0x1e,
206    RdMsr = 0x1f,
207    WrMsr = 0x20,
208    MapGpa = 0x10001,
209}
210
211open_enum! {
212    /// Result code for `tdcall` to the TDX module, returned in RAX.
213    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
214    pub enum TdCallResultCode: u32 {
215        SUCCESS = 0x00000000,
216        NON_RECOVERABLE_VCPU = 0x40000001,
217        NON_RECOVERABLE_TD = 0x60000002,
218        INTERRUPTED_RESUMABLE = 0x80000003,
219        INTERRUPTED_RESTARTABLE = 0x80000004,
220        NON_RECOVERABLE_TD_NON_ACCESSIBLE = 0x60000005,
221        INVALID_RESUMPTION = 0xC0000006,
222        NON_RECOVERABLE_TD_WRONG_APIC_MODE = 0xE0000007,
223        CROSS_TD_FAULT = 0x80000008,
224        CROSS_TD_TRAP = 0x90000009,
225        NON_RECOVERABLE_TD_CORRUPTED_MD = 0x6000000A,
226        OPERAND_INVALID = 0xC0000100,
227        OPERAND_ADDR_RANGE_ERROR = 0xC0000101,
228        OPERAND_BUSY = 0x80000200,
229        PREVIOUS_TLB_EPOCH_BUSY = 0x80000201,
230        SYS_BUSY = 0x80000202,
231        RND_NO_ENTROPY = 0x80000203,
232        OPERAND_BUSY_HOST_PRIORITY = 0x80000204,
233        HOST_PRIORITY_BUSY_TIMEOUT = 0x90000205,
234        PAGE_METADATA_INCORRECT = 0xC0000300,
235        PAGE_ALREADY_FREE = 0x00000301,
236        PAGE_NOT_OWNED_BY_TD = 0xC0000302,
237        PAGE_NOT_FREE = 0xC0000303,
238        TD_ASSOCIATED_PAGES_EXIST = 0xC0000400,
239        SYS_INIT_NOT_PENDING = 0xC0000500,
240        SYS_LP_INIT_NOT_DONE = 0xC0000502,
241        SYS_LP_INIT_DONE = 0xC0000503,
242        SYS_NOT_READY = 0xC0000505,
243        SYS_SHUTDOWN = 0xC0000506,
244        SYS_KEY_CONFIG_NOT_PENDING = 0xC0000507,
245        SYS_STATE_INCORRECT = 0xC0000508,
246        SYS_INVALID_HANDOFF = 0xC0000509,
247        SYS_INCOMPATIBLE_SIGSTRUCT = 0xC000050A,
248        SYS_LP_INIT_NOT_PENDING = 0xC000050B,
249        SYS_CONFIG_NOT_PENDING = 0xC000050C,
250        INCOMPATIBLE_SEAM_CAPABILITIES = 0xC000050D,
251        TD_FATAL = 0xE0000604,
252        TD_NON_DEBUG = 0xC0000605,
253        TDCS_NOT_ALLOCATED = 0xC0000606,
254        LIFECYCLE_STATE_INCORRECT = 0xC0000607,
255        OP_STATE_INCORRECT = 0xC0000608,
256        NO_VCPUS = 0xC0000609,
257        TDCX_NUM_INCORRECT = 0xC0000610,
258        VCPU_STATE_INCORRECT = 0xC0000700,
259        VCPU_ASSOCIATED = 0x80000701,
260        VCPU_NOT_ASSOCIATED = 0x80000702,
261        NO_VALID_VE_INFO = 0xC0000704,
262        MAX_VCPUS_EXCEEDED = 0xC0000705,
263        TSC_ROLLBACK = 0xC0000706,
264        TD_VMCS_FIELD_NOT_INITIALIZED = 0xC0000730,
265        MCS_FIELD_ERROR = 0xC0000731,
266        KEY_GENERATION_FAILED = 0x80000800,
267        TD_KEYS_NOT_CONFIGURED = 0x80000810,
268        KEY_STATE_INCORRECT = 0xC0000811,
269        KEY_CONFIGURED = 0x00000815,
270        WBCACHE_NOT_COMPLETE = 0x80000817,
271        HKID_NOT_FREE = 0xC0000820,
272        NO_HKID_READY_TO_WBCACHE = 0x00000821,
273        WBCACHE_RESUME_ERROR = 0xC0000823,
274        FLUSHVP_NOT_DONE = 0x80000824,
275        NUM_ACTIVATED_HKIDS_NOT_SUPPORTED = 0xC0000825,
276        INCORRECT_CPUID_VALUE = 0xC0000900,
277        LIMIT_CPUID_MAXVAL_SET = 0xC0000901,
278        INCONSISTENT_CPUID_FIELD = 0xC0000902,
279        CPUID_MAX_SUBLEAVES_UNRECOGNIZED = 0xC0000903,
280        CPUID_LEAF_1F_FORMAT_UNRECOGNIZED = 0xC0000904,
281        INVALID_WBINVD_SCOPE = 0xC0000905,
282        INVALID_PKG_ID = 0xC0000906,
283        ENABLE_MONITOR_FSM_NOT_SET = 0xC0000907,
284        CPUID_LEAF_NOT_SUPPORTED = 0xC0000908,
285        SMRR_NOT_LOCKED = 0xC0000910,
286        INVALID_SMRR_CONFIGURATION = 0xC0000911,
287        SMRR_OVERLAPS_CMR = 0xC0000912,
288        SMRR_LOCK_NOT_SUPPORTED = 0xC0000913,
289        SMRR_NOT_SUPPORTED = 0xC0000914,
290        INCONSISTENT_MSR = 0xC0000920,
291        INCORRECT_MSR_VALUE = 0xC0000921,
292        SEAMREPORT_NOT_AVAILABLE = 0xC0000930,
293        SEAMDB_GETREF_NOT_AVAILABLE = 0xC0000931,
294        SEAMDB_REPORT_NOT_AVAILABLE = 0xC0000932,
295        SEAMVERIFYREPORT_NOT_AVAILABLE = 0xC0000933,
296        INVALID_TDMR = 0xC0000A00,
297        NON_ORDERED_TDMR = 0xC0000A01,
298        TDMR_OUTSIDE_CMRS = 0xC0000A02,
299        TDMR_ALREADY_INITIALIZED = 0x00000A03,
300        INVALID_PAMT = 0xC0000A10,
301        PAMT_OUTSIDE_CMRS = 0xC0000A11,
302        PAMT_OVERLAP = 0xC0000A12,
303        INVALID_RESERVED_IN_TDMR = 0xC0000A20,
304        NON_ORDERED_RESERVED_IN_TDMR = 0xC0000A21,
305        CMR_LIST_INVALID = 0xC0000A22,
306        EPT_WALK_FAILED = 0xC0000B00,
307        EPT_ENTRY_FREE = 0xC0000B01,
308        EPT_ENTRY_NOT_FREE = 0xC0000B02,
309        EPT_ENTRY_NOT_PRESENT = 0xC0000B03,
310        EPT_ENTRY_NOT_LEAF = 0xC0000B04,
311        EPT_ENTRY_LEAF = 0xC0000B05,
312        GPA_RANGE_NOT_BLOCKED = 0xC0000B06,
313        GPA_RANGE_ALREADY_BLOCKED = 0x00000B07,
314        TLB_TRACKING_NOT_DONE = 0xC0000B08,
315        EPT_INVALID_PROMOTE_CONDITIONS = 0xC0000B09,
316        PAGE_ALREADY_ACCEPTED = 0x00000B0A,
317        PAGE_SIZE_MISMATCH = 0xC0000B0B,
318        GPA_RANGE_BLOCKED = 0xC0000B0C,
319        EPT_ENTRY_STATE_INCORRECT = 0xC0000B0D,
320        EPT_PAGE_NOT_FREE = 0xC0000B0E,
321        L2_SEPT_WALK_FAILED = 0xC0000B0F,
322        L2_SEPT_ENTRY_NOT_FREE = 0xC0000B10,
323        PAGE_ATTR_INVALID = 0xC0000B11,
324        L2_SEPT_PAGE_NOT_PROVIDED = 0xC0000B12,
325        METADATA_FIELD_ID_INCORRECT = 0xC0000C00,
326        METADATA_FIELD_NOT_WRITABLE = 0xC0000C01,
327        METADATA_FIELD_NOT_READABLE = 0xC0000C02,
328        METADATA_FIELD_VALUE_NOT_VALID = 0xC0000C03,
329        METADATA_LIST_OVERFLOW = 0xC0000C04,
330        INVALID_METADATA_LIST_HEADER = 0xC0000C05,
331        REQUIRED_METADATA_FIELD_MISSING = 0xC0000C06,
332        METADATA_ELEMENT_SIZE_INCORRECT = 0xC0000C07,
333        METADATA_LAST_ELEMENT_INCORRECT = 0xC0000C08,
334        METADATA_FIELD_CURRENTLY_NOT_WRITABLE = 0xC0000C09,
335        METADATA_WR_MASK_NOT_VALID = 0xC0000C0A,
336        METADATA_FIRST_FIELD_ID_IN_CONTEXT = 0x00000C0B,
337        METADATA_FIELD_SKIP = 0x00000C0C,
338        SERVTD_ALREADY_BOUND_FOR_TYPE = 0xC0000D00,
339        SERVTD_TYPE_MISMATCH = 0xC0000D01,
340        SERVTD_ATTR_MISMATCH = 0xC0000D02,
341        SERVTD_INFO_HASH_MISMATCH = 0xC0000D03,
342        SERVTD_UUID_MISMATCH = 0xC0000D04,
343        SERVTD_NOT_BOUND = 0xC0000D05,
344        SERVTD_BOUND = 0xC0000D06,
345        TARGET_UUID_MISMATCH = 0xC0000D07,
346        TARGET_UUID_UPDATED = 0xC0000D08,
347        INVALID_MBMD = 0xC0000E00,
348        INCORRECT_MBMD_MAC = 0xC0000E01,
349        NOT_WRITE_BLOCKED = 0xC0000E02,
350        ALREADY_WRITE_BLOCKED = 0x00000E03,
351        NOT_EXPORTED = 0xC0000E04,
352        MIGRATION_STREAM_STATE_INCORRECT = 0xC0000E05,
353        MAX_MIGS_NUM_EXCEEDED = 0xC0000E06,
354        EXPORTED_DIRTY_PAGES_REMAIN = 0xC0000E07,
355        MIGRATION_DECRYPTION_KEY_NOT_SET = 0xC0000E08,
356        TD_NOT_MIGRATABLE = 0xC0000E09,
357        PREVIOUS_EXPORT_CLEANUP_INCOMPLETE = 0xC0000E0A,
358        NUM_MIGS_HIGHER_THAN_CREATED = 0xC0000E0B,
359        IMPORT_MISMATCH = 0xC0000E0C,
360        MIGRATION_EPOCH_OVERFLOW = 0xC0000E0D,
361        MAX_EXPORTS_EXCEEDED = 0xC0000E0E,
362        INVALID_PAGE_MAC = 0xC0000E0F,
363        MIGRATED_IN_CURRENT_EPOCH = 0xC0000E10,
364        DISALLOWED_IMPORT_OVER_REMOVED = 0xC0000E11,
365        SOME_VCPUS_NOT_MIGRATED = 0xC0000E12,
366        ALL_VCPUS_IMPORTED = 0xC0000E13,
367        MIN_MIGS_NOT_CREATED = 0xC0000E14,
368        VCPU_ALREADY_EXPORTED = 0xC0000E15,
369        INVALID_MIGRATION_DECRYPTION_KEY = 0xC0000E16,
370        INVALID_CPUSVN = 0xC0001000,
371        INVALID_REPORTMACSTRUCT = 0xC0001001,
372        L2_EXIT_HOST_ROUTED_ASYNC = 0x00001100,
373        L2_EXIT_HOST_ROUTED_TDVMCALL = 0x00001101,
374        L2_EXIT_PENDING_INTERRUPT = 0x00001102,
375        PENDING_INTERRUPT = 0x00001120,
376        TD_EXIT_BEFORE_L2_ENTRY = 0x00001140,
377        TD_EXIT_ON_L2_VM_EXIT = 0x00001141,
378        TD_EXIT_ON_L2_TO_L1 = 0x00001142,
379        GLA_NOT_CANONICAL = 0xC0001160,
380    }
381}
382
383impl TdCallResultCode {
384    const fn from_bits(value: u64) -> Self {
385        Self(value as u32)
386    }
387
388    const fn into_bits(self) -> u64 {
389        self.0 as u64
390    }
391}
392
393/// The result returned by a tdcall instruction in rax.
394#[bitfield(u64)]
395pub struct TdCallResult {
396    pub details: u32,
397    #[bits(32)]
398    pub code: TdCallResultCode,
399}
400
401open_enum! {
402    /// The result returned by a tdg.vm.call in r10.
403    #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
404    pub enum TdVmCallR10Result: u64 {
405        SUCCESS = 0,
406        RETRY = 1,
407        OPERAND_INVALID = 0x80000000_00000000,
408        GPA_INUSE = 0x80000000_00000001,
409        ALIGN_ERROR = 0x80000000_00000002,
410    }
411}
412
413/// Field size for [`TdxExtendedFieldCode`].
414#[repr(u64)]
415#[derive(Debug)]
416pub enum FieldSize {
417    Invalid = 0,
418    Size16Bit = 1,
419    Size32Bit = 2,
420    Size64Bit = 3,
421}
422
423impl FieldSize {
424    const fn from_bits(value: u64) -> Self {
425        match value {
426            0 => FieldSize::Invalid,
427            1 => FieldSize::Size16Bit,
428            2 => FieldSize::Size32Bit,
429            3 => FieldSize::Size64Bit,
430            _ => panic!("Invalid field size"),
431        }
432    }
433
434    const fn into_bits(self) -> u64 {
435        self as u64
436    }
437}
438
439open_enum! {
440    pub enum TdVpsClassCode: u8 {
441        TD_VMCS = 0,
442        VAPIC = 1,
443        VE_INFO = 2,
444        GUEST_GPR_STATE = 16,
445        GUEST_STATE = 17,
446        GUEST_EXT_STATE = 18,
447        GUEST_MSR_STATE = 19,
448        MANAGEMENT = 32,
449        CPUID_CONTROL = 33,
450        EPT_VIOLATION_LOG = 34,
451        VMCS_1 = 36,
452        MSR_BITMAPS_1 = 37,
453        MSR_BITMAPS_SHADOW_1 = 38,
454        VMCS_2 = 44,
455        MSR_BITMAPS_2 = 45,
456        MSR_BITMAPS_SHADOW_2 = 46,
457        VMCS_3 = 52,
458    }
459}
460
461open_enum! {
462    pub enum TdxContextCode: u8 {
463        PLATFORM = 0,
464        TD = 1,
465        TD_VCPU = 2,
466    }
467}
468
469impl TdxContextCode {
470    const fn from_bits(value: u64) -> Self {
471        Self(value as u8)
472    }
473    const fn into_bits(self) -> u64 {
474        self.0 as u64
475    }
476}
477
478pub const TDX_FIELD_CODE_L2_CTLS_VM1: TdxExtendedFieldCode =
479    TdxExtendedFieldCode(0xA020000300000051);
480pub const TDX_FIELD_CODE_L2_CTLS_VM2: TdxExtendedFieldCode =
481    TdxExtendedFieldCode(0xA020000300000051);
482
483/// Extended field code for TDG.VP.WR and TDG.VP.RD
484#[bitfield(u64)]
485pub struct TdxExtendedFieldCode {
486    #[bits(24)]
487    pub field_code: u32,
488    #[bits(8)]
489    _reserved0: u64,
490    #[bits(2)]
491    pub field_size: FieldSize,
492    #[bits(4)]
493    pub last_element: u8,
494    #[bits(9)]
495    pub last_field: u16,
496    #[bits(3)]
497    _reserved1: u64,
498    pub increment_size: bool,
499    pub write_mask_valid: bool,
500    #[bits(3)]
501    pub context_code: TdxContextCode,
502    #[bits(1)]
503    _reserved2: u64,
504    #[bits(6)]
505    pub class_code: u8,
506    #[bits(1)]
507    _reserved3: u64,
508    pub non_arch: bool,
509}
510
511/// Instruction info returned in r11 for a TDG.VP.ENTER call.
512#[bitfield(u64)]
513pub struct TdxInstructionInfo {
514    pub info: u32,
515    pub length: u32,
516}
517
518#[bitfield(u64)]
519pub struct TdxL2Ctls {
520    pub enable_shared_ept: bool,
521    pub enable_tdvmcall: bool,
522    #[bits(62)]
523    pub reserved: u64,
524}
525
526#[bitfield(u64)]
527pub struct TdxVpEnterRaxResult {
528    /// The VMX exit code for VP.ENTER, if valid.
529    #[bits(32)]
530    pub vmx_exit: vmx::VmxExit,
531    /// The TDX specific exit code.
532    #[bits(32)]
533    pub tdx_exit: TdCallResultCode,
534}
535
536#[bitfield(u64)]
537pub struct TdxExtendedExitQualification {
538    #[bits(4)]
539    pub ty: TdxExtendedExitQualificationType,
540    #[bits(60)]
541    _reserved: u64,
542}
543
544open_enum! {
545    pub enum TdxExtendedExitQualificationType: u8 {
546        NONE = 0,
547        PENDING_EPT_VIOLATION = 6,
548    }
549}
550
551impl TdxExtendedExitQualificationType {
552    const fn from_bits(value: u64) -> Self {
553        Self(value as u8)
554    }
555
556    const fn into_bits(self) -> u64 {
557        self.0 as u64
558    }
559}
560
561/// The GPR list used for TDG.VP.ENTER. Specified in the TDX specification as
562/// L2_ENTER_GUEST_STATE.
563#[repr(C)]
564#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
565pub struct TdxL2EnterGuestState {
566    /// GPs in the usual order.
567    pub gps: [u64; 16],
568    pub rflags: u64,
569    pub rip: u64,
570    pub ssp: u64,
571    pub rvi: u8, // GUEST_INTERRUPT_STATUS lower bits
572    pub svi: u8, // GUEST_INTERRUPT_STATUS upper bits
573    pub reserved: [u8; 6],
574}
575
576pub enum TdxGp {}
577impl TdxGp {
578    pub const RAX: usize = 0;
579    pub const RCX: usize = 1;
580    pub const RDX: usize = 2;
581    pub const RBX: usize = 3;
582    pub const RSP: usize = 4;
583    pub const RBP: usize = 5;
584    pub const RSI: usize = 6;
585    pub const RDI: usize = 7;
586    pub const R8: usize = 8;
587    pub const R9: usize = 9;
588    pub const R10: usize = 10;
589    pub const R11: usize = 11;
590    pub const R12: usize = 12;
591    pub const R13: usize = 13;
592    pub const R14: usize = 14;
593    pub const R15: usize = 15;
594}
595
596#[bitfield(u64)]
597pub struct TdxGlaListInfo {
598    #[bits(9)]
599    pub first_entry: u64,
600    #[bits(3)]
601    _reserved_z0: u64,
602    #[bits(40)]
603    pub list_gpa: u64,
604    #[bits(10)]
605    pub num_entries: u64,
606    #[bits(2)]
607    _reserved_z1: u64,
608}
609
610#[bitfield(u64)]
611pub struct TdGlaVmAndFlags {
612    pub list: bool,
613    #[bits(51)]
614    _reserved_z0: u64,
615    #[bits(2)]
616    pub vm_index: u64,
617    #[bits(10)]
618    _reserved_z1: u64,
619}
620
621#[bitfield(u64)]
622#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
623pub struct TdxVmFlags {
624    #[bits(2)]
625    pub invd_translations: u8,
626
627    #[bits(50)]
628    _reserved: u64,
629
630    /// Starts at 1, not 0.
631    #[bits(2)]
632    pub vm_index: u8,
633
634    #[bits(10)]
635    _reserved_2: u64,
636}
637
638pub const TDX_VP_ENTER_INVD_INVEPT: u8 = 1;
639pub const TDX_VP_ENTER_INVD_INVVPID: u8 = 2;
640pub const TDX_VP_ENTER_INVD_INVVPID_NON_GLOBAL: u8 = 3;
641
642/// Report structure.
643/// See `TDREPORT_STRUCT` in Table 3.29, "Intel TDX Module v1.5 ABI specification", March 2024.
644#[repr(C)]
645#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
646pub struct TdReport {
647    /// An instance of [`ReportMac`]
648    pub report_mac_struct: ReportMac,
649    /// An instance of [`TeeTcbInfo`].
650    pub tee_tcb_info: TeeTcbInfo,
651    /// Reserved
652    pub _reserved: [u8; 17],
653    /// An instance of [`TdInfo`].
654    pub td_info: TdInfo,
655}
656
657static_assertions::const_assert_eq!(TDX_REPORT_SIZE, size_of::<TdReport>());
658
659/// See `REPORTMACSTRUCT` in Table 3.31, "Intel TDX Module v1.5 ABI specification", March 2024.
660#[repr(C)]
661#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
662pub struct ReportMac {
663    /// Type header structure
664    pub report_type: ReportType,
665    /// Must be zero
666    pub _reserved0: [u8; 12],
667    /// CPU SVN
668    pub cpu_svn: [u8; 16],
669    /// SHA384 of [`TeeTcbInfo`]
670    pub tee_tcb_info_hash: [u8; 48],
671    /// SHA384 of [`TdInfo`] for TDX
672    pub tee_info_hash: [u8; 48],
673    /// A set of data used for communication between the caller and the target
674    pub report_data: [u8; TDX_REPORT_DATA_SIZE],
675    /// Must be zero
676    pub _reserved1: [u8; 32],
677    /// The MAC over above data.
678    pub mac: [u8; 32],
679}
680
681/// See `REPORTTYPE` in Table 3.32, "Intel TDX Module v1.5 ABI specification", March 2024.
682#[repr(C)]
683#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
684pub struct ReportType {
685    /// TEE type
686    /// 0x00: SGX
687    /// 0x81: TDX
688    pub tee_type: u8,
689    /// TEE type-specific subtype
690    /// 0: Standard TDX report
691    pub sub_type: u8,
692    /// TEE type-specific version
693    /// For TDX
694    ///    0: `TDINFO_STRUCT.SERVTD_HASH` is not used (all 0's)
695    ///    1: `TDINFO_STRUCT.SERVTD_HASH` is used
696    pub version: u8,
697    /// Must be zero
698    pub _reserved: u8,
699}
700
701/// See `TEE_TCB_INFO` in Table 3.29, "Intel TDX Module v1.5 ABI specification", March 2024.
702#[repr(C)]
703#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
704pub struct TeeTcbInfo {
705    /// Indicates which fields are valid.
706    /// Set to 0x301ff.
707    pub valid: [u8; 8],
708    /// [`TeeTcbSvn`] of the TDX module that created the TD on the current
709    /// platform.
710    pub tee_tcb_svn: TeeTcbSvn,
711    /// The measurement of the TDX module that created the TD on the
712    /// current platform.
713    pub mr_seam: [u8; 48],
714    /// Set to all 0's.
715    pub mr_signer_seam: [u8; 48],
716    /// Set to all 0's.
717    pub attributes: [u8; 8],
718    /// [`TeeTcbSvn`] of the current TDX module on the current platform.
719    pub tee_tcb_svn2: TeeTcbSvn,
720    /// Reserved
721    pub reserved: [u8; 95],
722}
723
724/// See `TEE_TCB_SVN` in Section 3.9.4, "Intel TDX Module v1.5 ABI specification", March 2024.
725#[repr(C)]
726#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
727pub struct TeeTcbSvn {
728    /// TDX module minor SVN
729    pub tdx_module_svn_minor: u8,
730    /// TDX module major SVN
731    pub tdx_module_svn_major: u8,
732    /// Microcode SE_SVN at the time the TDX module was loaded
733    pub seam_last_patch_svn: u8,
734    /// Reserved
735    pub _reserved: [u8; 13],
736}
737
738/// See `TDINFO_STRUCT` in Table 3.33, "Intel TDX Module v1.5 ABI specification", March 2024.
739#[repr(C)]
740#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
741pub struct TdInfo {
742    /// An instance of [`TdInfoBase`]
743    pub td_info_base: TdInfoBase,
744    /// Must be zero when `version` in [`ReportType`] is 0 or 1.
745    pub td_info_extension: [u8; 64],
746}
747
748/// Run-time extendable measurement register.
749pub type Rtmr = [u8; 48];
750
751/// See `ATTRIBUTES` in Table 3.9, "Intel TDX Module v1.5 ABI specification", March 2024.
752#[bitfield(u64)]
753#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
754pub struct TdAttributes {
755    #[bits(1)]
756    pub debug: bool,
757    #[bits(3)]
758    _reserved1: u8,
759    #[bits(1)]
760    pub hgs_plus_prof: bool,
761    #[bits(1)]
762    pub perf_prof: bool,
763    #[bits(1)]
764    pub pmt_prof: bool,
765    #[bits(9)]
766    _reserved2: u16,
767    #[bits(7)]
768    _reserved_p: u8,
769    #[bits(4)]
770    _reserved_n: u8,
771    #[bits(1)]
772    pub lass: bool,
773    #[bits(1)]
774    pub sept_ve_disable: bool,
775    #[bits(1)]
776    pub migratable: bool,
777    #[bits(1)]
778    pub pks: bool,
779    #[bits(1)]
780    pub kl: bool,
781    #[bits(24)]
782    _reserved3: u32,
783    #[bits(6)]
784    _reserved4: u32,
785    #[bits(1)]
786    pub tpa: bool,
787    #[bits(1)]
788    pub perfmon: bool,
789}
790
791/// See `TDINFO_BASE` in Table 3.34, "Intel TDX Module v1.5 ABI specification", March 2024.
792#[repr(C)]
793#[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
794pub struct TdInfoBase {
795    /// TD's attributes
796    pub attributes: TdAttributes,
797    /// TD's XFAM
798    pub xfam: [u8; 8],
799    /// Measurement of the initial contents of the TDX in SHA384
800    pub mr_td: [u8; 48],
801    /// Software-defined ID for non-owner-defined configuration of the guest TD
802    /// in SHA384
803    pub mr_config_id: [u8; 48],
804    /// Software-defined ID for the guest TD's owner in SHA384
805    pub mr_owner: [u8; 48],
806    /// Software-defined ID for owner-defined configuration of the guest TD
807    /// in SHA384
808    pub mr_owner_config: [u8; 48],
809    /// Array of 4 [`Rtmr`]
810    pub rtmr: [Rtmr; 4],
811    /// SHA384 of the `TDINFO_STRUCTs` of bound service TDs if there is any.
812    pub servd_hash: [u8; 48],
813}