1use 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 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#[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#[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
79impl 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#[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 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#[bitfield(u64)]
116#[derive(PartialEq, Eq)]
117pub struct TdgMemPageGpaAttr {
118 #[bits(16)]
120 pub l1: GpaVmAttributes,
121 #[bits(16)]
123 pub l2_vm1: GpaVmAttributes,
124 #[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 #[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 #[bits(40)]
152 pub gpa_page_number: u64,
153 #[bits(10)]
154 pub reserved2: u64,
155 #[bits(1)]
158 pub pending: u8,
159 #[bits(1)]
160 pub reserved3: u64,
161}
162
163#[bitfield(u64)]
165#[derive(PartialEq, Eq)]
166pub struct TdgMemPageAttrWriteRcx {
167 #[bits(3)]
168 pub level: TdgMemPageLevel,
169 #[bits(9)]
170 pub reserved: u64,
171 #[bits(40)]
173 pub gpa_page_number: u64,
174 #[bits(12)]
175 pub reserved2: u64,
176}
177
178#[bitfield(u64)]
180pub struct TdgMemPageAttrWriteR8 {
181 #[bits(16)]
182 pub reserved: u64,
183 #[bits(16)]
185 pub l2_vm1: GpaVmAttributesMask,
186 #[bits(16)]
188 pub l2_vm2: GpaVmAttributesMask,
189 #[bits(16)]
191 pub l2_vm3: GpaVmAttributesMask,
192}
193
194#[repr(u64)]
197pub enum TdVmCallSubFunction {
198 IoInstr = 0x1e,
199 RdMsr = 0x1f,
200 WrMsr = 0x20,
201 MapGpa = 0x10001,
202}
203
204open_enum! {
205 #[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#[bitfield(u64)]
388pub struct TdCallResult {
389 pub details: u32,
390 #[bits(32)]
391 pub code: TdCallResultCode,
392}
393
394open_enum! {
395 #[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#[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#[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#[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 #[bits(32)]
523 pub vmx_exit: vmx::VmxExit,
524 #[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#[repr(C)]
557#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
558pub struct TdxL2EnterGuestState {
559 pub gps: [u64; 16],
561 pub rflags: u64,
562 pub rip: u64,
563 pub ssp: u64,
564 pub rvi: u8, pub svi: u8, 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 #[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;