1use super::Hcl;
7use super::HclVp;
8use super::MshvVtl;
9use super::NoRunner;
10use super::ProcessorRunner;
11use super::hcl_tdcall;
12use super::mshv_tdcall;
13use crate::GuestVtl;
14use crate::protocol::tdx_l2_tsc_deadline_state;
15use crate::protocol::tdx_tdg_vp_enter_exit_info;
16use crate::protocol::tdx_vp_context;
17use crate::protocol::tdx_vp_state;
18use crate::protocol::tdx_vp_state_flags;
19use hv1_structs::VtlArray;
20use hvdef::HvRegisterName;
21use hvdef::HvRegisterValue;
22use memory_range::MemoryRange;
23use sidecar_client::SidecarVp;
24use std::cell::UnsafeCell;
25use std::os::fd::AsRawFd;
26use tdcall::Tdcall;
27use tdcall::TdgPageReleaseError;
28use tdcall::tdcall_sys_rd;
29use tdcall::tdcall_vm_rd;
30use tdcall::tdcall_vm_wr;
31use tdcall::tdcall_vp_invgla;
32use tdcall::tdcall_vp_rd;
33use tdcall::tdcall_vp_wr;
34use x86defs::tdx::TDX_FIELD_CODE_CONFIG_FLAGS;
35use x86defs::tdx::TdCallResult;
36use x86defs::tdx::TdCallResultCode;
37use x86defs::tdx::TdConfigFlags;
38use x86defs::tdx::TdGlaVmAndFlags;
39use x86defs::tdx::TdVpsClassCode;
40use x86defs::tdx::TdgMemPageAttrWriteR8;
41use x86defs::tdx::TdgMemPageGpaAttr;
42use x86defs::tdx::TdxContextCode;
43use x86defs::tdx::TdxExtendedFieldCode;
44use x86defs::tdx::TdxGlaListInfo;
45use x86defs::tdx::TdxGp;
46use x86defs::tdx::TdxL2Ctls;
47use x86defs::tdx::TdxL2EnterGuestState;
48use x86defs::tdx::TdxVmFlags;
49use x86defs::vmx::VmcsField;
50use x86defs::vmx::VmxApicPage;
51
52pub struct Tdx<'a> {
54 apic_pages: VtlArray<&'a UnsafeCell<VmxApicPage>, 2>,
55}
56
57impl MshvVtl {
58 pub fn tdx_set_page_attributes(
60 &self,
61 range: MemoryRange,
62 attributes: TdgMemPageGpaAttr,
63 mask: TdgMemPageAttrWriteR8,
64 ) -> Result<(), TdCallResultCode> {
65 tdcall::set_page_attributes(&mut MshvVtlTdcall(self), range, attributes, mask)
66 }
67
68 pub fn tdx_accept_pages(
75 &self,
76 range: MemoryRange,
77 attributes: Option<(TdgMemPageGpaAttr, TdgMemPageAttrWriteR8)>,
78 ) -> Result<(), tdcall::AcceptPagesError> {
79 let attributes = attributes
80 .map_or(tdcall::AcceptPagesAttributes::None, |(attributes, mask)| {
81 tdcall::AcceptPagesAttributes::Set { attributes, mask }
82 });
83
84 tdcall::accept_pages(&mut MshvVtlTdcall(self), range, attributes)
85 }
86
87 pub fn tdx_release_pages(&self, range: MemoryRange) -> Result<(), TdgPageReleaseError> {
89 tdcall::release_pages(&mut MshvVtlTdcall(self), range)
90 }
91
92 pub fn tdx_get_config_flags(&self) -> TdConfigFlags {
94 let res = tdcall_vm_rd(&mut MshvVtlTdcall(self), TDX_FIELD_CODE_CONFIG_FLAGS)
95 .expect("TDG.VM.RD should not fail for CONFIG_FLAGS");
96
97 TdConfigFlags::from_bits(res)
98 }
99
100 pub fn tdx_read_features0(&self) -> Result<x86defs::tdx::TdxFeatures0, TdCallResult> {
107 let value = tdcall_sys_rd(
108 &mut MshvVtlTdcall(self),
109 x86defs::tdx::TDX_FIELD_ID_TDX_FEATURES0,
110 )?;
111 Ok(x86defs::tdx::TdxFeatures0::from(value))
112 }
113
114 pub fn tdx_enable_hw_seal_keys(&self) -> Result<bool, TdCallResult> {
128 let enable = x86defs::tdx::TdCtls::new().with_enable_hw_seal_keys(true);
129
130 tdcall_vm_wr(
132 &mut MshvVtlTdcall(self),
133 x86defs::tdx::TDX_FIELD_CODE_TD_CTLS,
134 enable.into(),
135 enable.into(),
136 )?;
137
138 let controls = x86defs::tdx::TdCtls::from(tdcall_vm_rd(
141 &mut MshvVtlTdcall(self),
142 x86defs::tdx::TDX_FIELD_CODE_TD_CTLS,
143 )?);
144
145 Ok(controls.enable_hw_seal_keys())
146 }
147}
148
149impl<'a> ProcessorRunner<'a, Tdx<'a>> {
150 fn tdx_vp_context(&self) -> &tdx_vp_context {
153 unsafe { &*(&raw mut (*self.run.get()).context).cast() }
157 }
158
159 fn tdx_vp_context_mut(&mut self) -> &mut tdx_vp_context {
162 unsafe { &mut *(&raw mut (*self.run.get()).context).cast() }
166 }
167
168 fn tdx_enter_guest_state(&self) -> &TdxL2EnterGuestState {
170 &self.tdx_vp_context().gpr_list
171 }
172
173 fn tdx_enter_guest_state_mut(&mut self) -> &mut TdxL2EnterGuestState {
175 &mut self.tdx_vp_context_mut().gpr_list
176 }
177
178 pub fn tdx_enter_guest_gps(&self) -> &[u64; 16] {
181 &self.tdx_enter_guest_state().gps
182 }
183
184 pub fn tdx_enter_guest_gps_mut(&mut self) -> &mut [u64; 16] {
187 &mut self.tdx_enter_guest_state_mut().gps
188 }
189
190 pub fn tdx_vp_enter_exit_info(&self) -> &tdx_tdg_vp_enter_exit_info {
192 &self.tdx_vp_context().exit_info
193 }
194
195 pub fn tdx_apic_page(&self, vtl: GuestVtl) -> &VmxApicPage {
197 unsafe { &*self.state.apic_pages[vtl].get() }
200 }
201
202 pub fn tdx_apic_page_mut(&mut self, vtl: GuestVtl) -> &mut VmxApicPage {
204 unsafe { &mut *self.state.apic_pages[vtl].get() }
207 }
208
209 fn tdx_vp_state(&self) -> &tdx_vp_state {
211 &self.tdx_vp_context().vp_state
212 }
213
214 fn tdx_vp_state_mut(&mut self) -> &mut tdx_vp_state {
216 &mut self.tdx_vp_context_mut().vp_state
217 }
218
219 pub fn cr2(&self) -> u64 {
221 self.tdx_vp_state().cr2
222 }
223
224 pub fn set_cr2(&mut self, value: u64) {
226 self.tdx_vp_state_mut().cr2 = value;
227 }
228
229 pub fn tdx_vp_state_flags_mut(&mut self) -> &mut tdx_vp_state_flags {
231 &mut self.tdx_vp_state_mut().flags
232 }
233
234 fn tdx_vp_entry_flags(&self) -> &TdxVmFlags {
236 &self.tdx_vp_context().entry_rcx
237 }
238
239 fn tdx_vp_entry_flags_mut(&mut self) -> &mut TdxVmFlags {
241 &mut self.tdx_vp_context_mut().entry_rcx
242 }
243
244 pub fn tdx_l2_tsc_deadline_state(&self) -> &tdx_l2_tsc_deadline_state {
246 &self.tdx_vp_context().l2_tsc_deadline
247 }
248
249 pub fn tdx_l2_tsc_deadline_state_mut(&mut self) -> &mut tdx_l2_tsc_deadline_state {
251 &mut self.tdx_vp_context_mut().l2_tsc_deadline
252 }
253
254 pub fn read_private_regs(&self, regs: &mut TdxPrivateRegs) {
257 let TdxL2EnterGuestState {
258 gps, rflags,
260 rip,
261 ssp,
262 rvi,
263 svi,
264 reserved: _reserved,
265 } = self.tdx_enter_guest_state();
266 regs.rflags = *rflags;
267 regs.rip = *rip;
268 regs.rsp = gps[TdxGp::RSP];
269 regs.ssp = *ssp;
270 regs.rvi = *rvi;
271 regs.svi = *svi;
272
273 let tdx_vp_state {
274 msr_kernel_gs_base,
275 msr_star,
276 msr_lstar,
277 msr_sfmask,
278 msr_xss,
279 cr2: _cr2, msr_tsc_aux,
281 flags: _flags, } = self.tdx_vp_state();
283 regs.msr_kernel_gs_base = *msr_kernel_gs_base;
284 regs.msr_star = *msr_star;
285 regs.msr_lstar = *msr_lstar;
286 regs.msr_sfmask = *msr_sfmask;
287 regs.msr_xss = *msr_xss;
288 regs.msr_tsc_aux = *msr_tsc_aux;
289
290 regs.vp_entry_flags = *self.tdx_vp_entry_flags();
291 }
292
293 pub fn write_private_regs(&mut self, regs: &TdxPrivateRegs) {
296 let TdxPrivateRegs {
297 rflags,
298 rip,
299 rsp,
300 ssp,
301 rvi,
302 svi,
303 msr_kernel_gs_base,
304 msr_star,
305 msr_lstar,
306 msr_sfmask,
307 msr_xss,
308 msr_tsc_aux,
309 vp_entry_flags,
310 } = regs;
311
312 let enter_guest_state = self.tdx_enter_guest_state_mut();
313 enter_guest_state.rflags = *rflags;
314 enter_guest_state.rip = *rip;
315 enter_guest_state.ssp = *ssp;
316 enter_guest_state.rvi = *rvi;
317 enter_guest_state.svi = *svi;
318 enter_guest_state.gps[TdxGp::RSP] = *rsp;
319
320 let vp_state = self.tdx_vp_state_mut();
321 vp_state.msr_kernel_gs_base = *msr_kernel_gs_base;
322 vp_state.msr_star = *msr_star;
323 vp_state.msr_lstar = *msr_lstar;
324 vp_state.msr_sfmask = *msr_sfmask;
325 vp_state.msr_xss = *msr_xss;
326 vp_state.msr_tsc_aux = *msr_tsc_aux;
327
328 *self.tdx_vp_entry_flags_mut() = *vp_entry_flags;
329 }
330
331 fn write_vmcs(&mut self, vtl: GuestVtl, field: VmcsField, mask: u64, value: u64) -> u64 {
332 tdcall_vp_wr(
333 &mut MshvVtlTdcall(&self.hcl.mshv_vtl),
334 vmcs_field_code(field, vtl),
335 value,
336 mask,
337 )
338 .expect("fatal vmcs access failure")
339 }
340
341 fn read_vmcs(&self, vtl: GuestVtl, field: VmcsField) -> u64 {
342 tdcall_vp_rd(
343 &mut MshvVtlTdcall(&self.hcl.mshv_vtl),
344 vmcs_field_code(field, vtl),
345 )
346 .expect("fatal vmcs access failure")
347 }
348
349 pub fn write_vmcs64(&mut self, vtl: GuestVtl, field: VmcsField, mask: u64, value: u64) -> u64 {
357 assert!(matches!(
358 field.field_width(),
359 x86defs::vmx::FieldWidth::WidthNatural | x86defs::vmx::FieldWidth::Width64
360 ));
361 self.write_vmcs(vtl, field, mask, value)
362 }
363
364 pub fn read_vmcs64(&self, vtl: GuestVtl, field: VmcsField) -> u64 {
369 assert!(matches!(
370 field.field_width(),
371 x86defs::vmx::FieldWidth::WidthNatural | x86defs::vmx::FieldWidth::Width64
372 ));
373 self.read_vmcs(vtl, field)
374 }
375
376 pub fn write_vmcs32(&mut self, vtl: GuestVtl, field: VmcsField, mask: u32, value: u32) -> u32 {
384 assert_eq!(field.field_width(), x86defs::vmx::FieldWidth::Width32);
385 self.write_vmcs(vtl, field, mask.into(), value.into()) as u32
386 }
387
388 pub fn read_vmcs32(&self, vtl: GuestVtl, field: VmcsField) -> u32 {
393 assert_eq!(field.field_width(), x86defs::vmx::FieldWidth::Width32);
394 self.read_vmcs(vtl, field) as u32
395 }
396
397 pub fn write_vmcs16(&mut self, vtl: GuestVtl, field: VmcsField, mask: u16, value: u16) -> u16 {
405 assert_eq!(field.field_width(), x86defs::vmx::FieldWidth::Width16);
406 self.write_vmcs(vtl, field, mask.into(), value.into()) as u16
407 }
408
409 pub fn read_vmcs16(&self, vtl: GuestVtl, field: VmcsField) -> u16 {
414 assert_eq!(field.field_width(), x86defs::vmx::FieldWidth::Width16);
415 self.read_vmcs(vtl, field) as u16
416 }
417
418 pub fn set_msr_bit(&self, vtl: GuestVtl, msr_index: u32, write: bool, intercept: bool) {
422 let mut word_index = (msr_index & 0xFFFF) / 64;
423
424 if msr_index & 0x80000000 == 0x80000000 {
425 assert!((0xC0000000..=0xC0001FFF).contains(&msr_index));
426 word_index += 0x80;
427 } else {
428 assert!(msr_index <= 0x00001FFF);
429 }
430
431 if write {
432 word_index += 0x100;
433 }
434
435 self.write_msr_bitmap(
436 vtl,
437 word_index,
438 1 << (msr_index as u64 & 0x3F),
439 if intercept { !0 } else { 0 },
440 );
441 }
442
443 pub fn write_msr_bitmap(&self, vtl: GuestVtl, i: u32, mask: u64, word: u64) -> u64 {
450 let class_code = match vtl {
451 GuestVtl::Vtl0 => TdVpsClassCode::MSR_BITMAPS_1,
452 GuestVtl::Vtl1 => TdVpsClassCode::MSR_BITMAPS_2,
453 };
454 let field_code = TdxExtendedFieldCode::new()
455 .with_context_code(TdxContextCode::TD_VCPU)
456 .with_field_size(x86defs::tdx::FieldSize::Size64Bit)
457 .with_field_code(i)
458 .with_class_code(class_code.0);
459
460 tdcall_vp_wr(
461 &mut MshvVtlTdcall(&self.hcl.mshv_vtl),
462 field_code,
463 word,
464 mask,
465 )
466 .unwrap()
467 }
468
469 pub fn set_l2_ctls(&self, vtl: GuestVtl, value: TdxL2Ctls) -> Result<TdxL2Ctls, TdCallResult> {
473 let field_code = match vtl {
474 GuestVtl::Vtl0 => x86defs::tdx::TDX_FIELD_CODE_L2_CTLS_VM1,
475 GuestVtl::Vtl1 => x86defs::tdx::TDX_FIELD_CODE_L2_CTLS_VM2,
476 };
477 tdcall_vp_wr(
478 &mut MshvVtlTdcall(&self.hcl.mshv_vtl),
479 field_code,
480 value.into(),
481 !0,
482 )
483 .map(Into::into)
484 }
485
486 pub fn invgla(
488 &self,
489 gla_flags: TdGlaVmAndFlags,
490 gla_info: TdxGlaListInfo,
491 ) -> Result<(), TdCallResult> {
492 tdcall_vp_invgla(&mut MshvVtlTdcall(&self.hcl.mshv_vtl), gla_flags, gla_info)
493 }
494
495 pub fn fx_state(&self) -> &x86defs::xsave::Fxsave {
497 &self.tdx_vp_context().fx_state
498 }
499
500 pub fn fx_state_mut(&mut self) -> &mut x86defs::xsave::Fxsave {
502 &mut self.tdx_vp_context_mut().fx_state
503 }
504}
505
506fn vmcs_field_code(field: VmcsField, vtl: GuestVtl) -> TdxExtendedFieldCode {
507 let class_code = match vtl {
508 GuestVtl::Vtl0 => TdVpsClassCode::VMCS_1,
509 GuestVtl::Vtl1 => TdVpsClassCode::VMCS_2,
510 };
511 let field_size = match field.field_width() {
512 x86defs::vmx::FieldWidth::Width16 => x86defs::tdx::FieldSize::Size16Bit,
513 x86defs::vmx::FieldWidth::Width32 => x86defs::tdx::FieldSize::Size32Bit,
514 x86defs::vmx::FieldWidth::Width64 => x86defs::tdx::FieldSize::Size64Bit,
515 x86defs::vmx::FieldWidth::WidthNatural => x86defs::tdx::FieldSize::Size64Bit,
516 };
517 TdxExtendedFieldCode::new()
518 .with_context_code(TdxContextCode::TD_VCPU)
519 .with_class_code(class_code.0)
520 .with_field_code(field.into())
521 .with_field_size(field_size)
522}
523
524impl<'a> super::private::BackingPrivate<'a> for Tdx<'a> {
525 fn new(vp: &'a HclVp, sidecar: Option<&SidecarVp<'_>>, hcl: &Hcl) -> Result<Self, NoRunner> {
526 assert!(sidecar.is_none());
527 let super::BackingState::Tdx {
528 vtl0_apic_page,
529 vtl1_apic_page,
530 } = &vp.backing
531 else {
532 return Err(NoRunner::MismatchedIsolation);
533 };
534
535 let vtl1_apic_page_addr = vtl1_apic_page.pfns()[0] * user_driver::memory::PAGE_SIZE64;
538 tdcall_vp_wr(
539 &mut MshvVtlTdcall(&hcl.mshv_vtl),
540 vmcs_field_code(VmcsField::VMX_VMCS_VIRTUAL_APIC_PAGE, GuestVtl::Vtl1),
541 vtl1_apic_page_addr,
542 !0,
543 )
544 .expect("failed registering VTL1 APIC page");
545
546 let vtl1_apic_page = unsafe { &*vtl1_apic_page.base().cast() };
549
550 Ok(Self {
551 apic_pages: [vtl0_apic_page.as_ref(), vtl1_apic_page].into(),
552 })
553 }
554
555 fn try_set_reg(
556 _runner: &mut ProcessorRunner<'a, Self>,
557 _vtl: GuestVtl,
558 _name: HvRegisterName,
559 _value: HvRegisterValue,
560 ) -> bool {
561 false
562 }
563
564 fn must_flush_regs_on(_runner: &ProcessorRunner<'a, Self>, _name: HvRegisterName) -> bool {
565 false
566 }
567
568 fn try_get_reg(
569 _runner: &ProcessorRunner<'a, Self>,
570 _vtl: GuestVtl,
571 _name: HvRegisterName,
572 ) -> Option<HvRegisterValue> {
573 None
574 }
575
576 fn flush_register_page(_runner: &mut ProcessorRunner<'a, Self>) {}
577}
578
579#[derive(inspect::InspectMut)]
581#[expect(missing_docs, reason = "Self-describing field names")]
582pub struct TdxPrivateRegs {
583 pub rflags: u64,
585 pub rip: u64,
586 pub rsp: u64,
587 pub ssp: u64,
588 pub rvi: u8,
589 pub svi: u8,
590 pub msr_kernel_gs_base: u64,
592 pub msr_star: u64,
593 pub msr_lstar: u64,
594 pub msr_sfmask: u64,
595 pub msr_xss: u64,
596 pub msr_tsc_aux: u64,
597 #[inspect(hex, with = "|x| x.into_bits()")]
599 pub vp_entry_flags: TdxVmFlags,
600}
601
602impl TdxPrivateRegs {
603 pub fn new(vtl: GuestVtl) -> Self {
606 Self {
607 rflags: x86defs::RFlags::at_reset().into(),
608 rip: 0,
609 rsp: 0,
610 ssp: 0,
611 rvi: 0,
612 svi: 0,
613 msr_kernel_gs_base: 0,
614 msr_star: 0,
615 msr_lstar: 0,
616 msr_sfmask: 0,
617 msr_xss: 0,
618 msr_tsc_aux: 0,
619 vp_entry_flags: TdxVmFlags::new()
624 .with_vm_index(vtl as u8 + 1)
625 .with_invd_translations(x86defs::tdx::TDX_VP_ENTER_INVD_INVEPT),
626 }
627 }
628}
629
630struct MshvVtlTdcall<'a>(&'a MshvVtl);
631
632impl Tdcall for MshvVtlTdcall<'_> {
633 fn tdcall(&mut self, input: tdcall::TdcallInput) -> tdcall::TdcallOutput {
634 let mut mshv_tdcall_args = {
635 let tdcall::TdcallInput {
636 leaf,
637 rcx,
638 rdx,
639 r8,
640 r9,
641 r10,
642 r11,
643 r12,
644 r13,
645 r14,
646 r15,
647 } = input;
648
649 assert_ne!(leaf, x86defs::tdx::TdCallLeaf::VP_VMCALL);
653 assert_eq!(r10, 0);
654 assert_eq!(r11, 0);
655 assert_eq!(r12, 0);
656 assert_eq!(r13, 0);
657 assert_eq!(r14, 0);
658 assert_eq!(r15, 0);
659
660 mshv_tdcall {
661 rax: leaf.0,
662 rcx,
663 rdx,
664 r8,
665 r9,
666 r10_out: 0,
667 r11_out: 0,
668 }
669 };
670
671 unsafe {
673 hcl_tdcall(self.0.file.as_raw_fd(), &mut mshv_tdcall_args)
676 .expect("todo handle tdcall ioctl error");
677 }
678
679 tdcall::TdcallOutput {
680 rax: TdCallResult::from(mshv_tdcall_args.rax),
681 rcx: mshv_tdcall_args.rcx,
682 rdx: mshv_tdcall_args.rdx,
683 r8: mshv_tdcall_args.r8,
684 r10: mshv_tdcall_args.r10_out,
685 r11: mshv_tdcall_args.r11_out,
686 }
687 }
688}