@@ -564,6 +564,7 @@ impl CpuidFeatureEntry {
564564pub fn generate_common_cpuid (
565565 hypervisor : & dyn hypervisor:: Hypervisor ,
566566 config : & CpuidConfig ,
567+ #[ cfg( feature = "tdx" ) ] vm : Option < & dyn hypervisor:: Vm > ,
567568) -> super :: Result < Vec < CpuIdEntry > > {
568569 #[ allow( unused_unsafe) ]
569570 // SAFETY: cpuid called with valid leaves
@@ -634,6 +635,16 @@ pub fn generate_common_cpuid(
634635
635636 CpuidPatch :: patch_cpuid ( & mut cpuid, & cpuid_patches) ;
636637
638+ #[ cfg( feature = "tdx" ) ]
639+ if config. tdx {
640+ let tdx_vm = vm. ok_or_else ( || {
641+ Error :: TdxCapabilities ( HypervisorVmError :: InitializeTdx ( std:: io:: Error :: other (
642+ "Missing VM instance for TDX CPUID generation" ,
643+ ) ) )
644+ } ) ?;
645+ common_cpuid_tdx_configuration ( & mut cpuid, tdx_vm) ?;
646+ }
647+
637648 // Update some existing CPUID
638649 for entry in cpuid. as_mut_slice ( ) . iter_mut ( ) {
639650 #[ allow( unused_unsafe) ]
@@ -648,9 +659,6 @@ pub fn generate_common_cpuid(
648659 entry. edx &= !( 1 << AMX_COMPLEX ) ;
649660 }
650661 }
651- 0xd =>
652- {
653- }
654662 // Tile Information (purely AMX related).
655663 0x1d if !config. amx => {
656664 entry. eax = 0 ;
@@ -792,6 +800,41 @@ pub fn generate_common_cpuid(
792800 Ok ( cpuid)
793801}
794802
803+ #[ cfg( feature = "tdx" ) ]
804+ fn common_cpuid_tdx_configuration (
805+ cpuid : & mut [ CpuIdEntry ] ,
806+ vm : & dyn hypervisor:: Vm ,
807+ ) -> super :: Result < ( ) > {
808+ let caps = vm. tdx_capabilities ( ) . map_err ( Error :: TdxCapabilities ) ?;
809+ debug ! ( "TDX capabilities supported_attrs={:#x} supported_xfam={:#x}" ,
810+ caps. supported_attrs, caps. supported_xfam) ;
811+
812+ // XCR0-managed (user) XSAVE state components. Must include the AMX
813+ // tile state components (XTILECFG bit 17, XTILEDATA bit 18); otherwise
814+ // AMX is stripped from CPUID.0xD.0 and never makes it into the TD XFAM.
815+ // Bits: x87(0) SSE(1) AVX(2) BNDREG(3) BNDCSR(4) OPMASK(5) ZMM_Hi256(6)
816+ // Hi16_ZMM(7) PKRU(9) XTILECFG(17) XTILEDATA(18).
817+ let xcr0_mask: u64 = 0x602ff ;
818+ // IA32_XSS-managed (supervisor) XSAVE state components currently defined
819+ // by the architecture. Listed explicitly (rather than `!xcr0_mask`) so
820+ // reserved/undefined bits (19-63) are masked to zero instead of relying
821+ // on `supported_xfam` to already be zero there.
822+ // Bits: PT(8) ENQCMD/PASID(10) CET_U(11) CET_S(12) HDC(13) UINTR(14)
823+ // LBR(15) HWP(16).
824+ let xss_mask: u64 = 0x1fd00 ;
825+ for entry in cpuid. iter_mut ( ) . filter ( |entry| entry. function == 0xd ) {
826+ if entry. index == 0 {
827+ entry. eax &= ( caps. supported_xfam as u32 ) & ( xcr0_mask as u32 ) ;
828+ entry. edx &= ( ( caps. supported_xfam & xcr0_mask) >> 32 ) as u32 ;
829+ } else if entry. index == 1 {
830+ entry. ecx &= ( caps. supported_xfam as u32 ) & ( xss_mask as u32 ) ;
831+ entry. edx &= ( ( caps. supported_xfam & xss_mask) >> 32 ) as u32 ;
832+ }
833+ }
834+
835+ Ok ( ( ) )
836+ }
837+
795838#[ allow( clippy:: too_many_arguments) ]
796839pub fn configure_vcpu (
797840 vcpu : & dyn hypervisor:: Vcpu ,
0 commit comments