@@ -104,6 +104,12 @@ pub fn functionally_same(base: CpuIdDump, target: CpuIdDump) -> bool {
104104 if base_info. has_fp256 ( ) != target_info. has_fp256 ( ) {
105105 return false ;
106106 }
107+
108+ // TODO: same as above: we probably just need to require "base" has
109+ // the same or wider FPU datapath than "target"
110+ if base_info. has_fp512 ( ) != target_info. has_fp512 ( ) {
111+ return false ;
112+ }
107113 }
108114 _ => {
109115 // Specific cases here may be acceptable, but for expediency (and
@@ -500,8 +506,8 @@ fn milan_ideal() -> CpuIdDump {
500506
501507 // Set up processor optimization info (leaf 8000_001Ah)
502508 let mut leaf = PerformanceOptimizationInfo :: empty ( ) ;
503- leaf. set_movu ( true ) ; // TODO: BREAKING
504- leaf. set_fp256 ( true ) ; // TODO: BREAKINGISH?
509+ leaf. set_movu ( true ) ;
510+ leaf. set_fp256 ( true ) ;
505511 cpuid
506512 . set_performance_optimization_info ( Some ( leaf) )
507513 . expect ( "can set leaf 8000_001Ah" ) ;
@@ -555,11 +561,21 @@ pub fn turin_v1() -> CpuIdDump {
555561
556562 let mut cpuid = CpuId :: with_cpuid_reader ( baseline) ;
557563
558- let mut leaf = cpuid. get_extended_feature_info ( )
564+ let mut leaf = cpuid
565+ . get_extended_feature_info ( )
559566 . expect ( "baseline Milan defines leaf 7" ) ;
560567
561- // These are the AVX512 features present on a 9365, when I'd looked in
562- // September, anyway
568+ // Turin supports the TSC_ADJUST MSR but guest plumbing is not present for
569+ // it and it's not clear what a guest would productively do with it anyway.
570+ leaf. set_tsc_adjust_msr ( false ) ;
571+
572+ // Turin supports MOVDIR64B and MOVDIRI. These instructions should just work
573+ // in guests, but it would be nice to test this before committing to passing
574+ // them.
575+ leaf. set_movdir64b ( false ) ;
576+ leaf. set_movdiri ( false ) ;
577+
578+ // These AVX512 features are present for all Turin processors.
563579 leaf. set_avx512f ( true ) ;
564580 leaf. set_avx512dq ( true ) ;
565581 leaf. set_avx512_ifma ( true ) ;
@@ -573,20 +589,77 @@ pub fn turin_v1() -> CpuIdDump {
573589 leaf. set_avx512vnni ( true ) ;
574590 leaf. set_avx512bitalg ( true ) ;
575591 leaf. set_avx512vpopcntdq ( true ) ;
592+ // While hardware supports 57-bit virtual addresses, the bhyve support is
593+ // not there yet.
594+ leaf. set_la57 ( false ) ;
595+
596+ leaf. set_avx512_vp2intersect ( true ) ;
576597
577598 leaf. set_avx512_bf16 ( true ) ;
578599 leaf. set_avx_vnni ( true ) ;
579600
580- cpuid. set_extended_feature_info ( Some ( leaf) )
581- . expect ( "can set leaf 7h" ) ;
601+ cpuid. set_extended_feature_info ( Some ( leaf) ) . expect ( "can set leaf 7h" ) ;
602+
603+ // This is the same information for leaf D as in Milan, but with the new
604+ // AVX-512 bits in Turin.
605+ // TODO: kind of gross to have to pass an empty `CpuIdDump` here...
606+ let mut state = ExtendedStateInfo :: empty ( CpuIdDump :: new ( ) ) ;
607+ state. set_xcr0_supports_legacy_x87 ( true ) ;
608+ state. set_xcr0_supports_sse_128 ( true ) ;
609+ state. set_xcr0_supports_avx_256 ( true ) ;
610+ // Update leaf D for the larger XCR0 set
611+ state. set_xcr0_supports_avx512_opmask ( true ) ;
612+ state. set_xcr0_supports_avx512_zmm_hi256 ( true ) ;
613+ state. set_xcr0_supports_avx512_zmm_hi16 ( true ) ;
614+ // Managed dynamically in practice.
615+ state. set_xsave_area_size_enabled_features ( 0x980 ) ;
616+ // `Core::X86::Cpuid::ProcExtStateEnumEcx00`, but minus the MPK support we
617+ // don't make available to guests.
618+ state. set_xsave_area_size_supported_features ( 0x980 ) ;
619+
620+ state. set_xsaveopt ( true ) ;
621+ state. set_xsavec ( true ) ;
622+ state. set_xgetbv ( true ) ;
623+ state. set_xsave_size ( 0x980 ) ;
624+
625+ let mut leaves = state. into_leaves ( ) . to_vec ( ) ;
626+ let mut ymm_state = ExtendedState :: empty ( ) ;
627+ ymm_state. set_size ( 0x100 ) ;
628+ ymm_state. set_offset ( 0x240 ) ;
629+ leaves. push ( Some ( ymm_state. into_leaf ( ) ) ) ;
630+ // level 3
631+ leaves. push ( None ) ;
632+ // level 4
633+ leaves. push ( None ) ;
634+ // levels 5, 6, and 7 are described in the PPR:
635+ // `Core::X86::Cpuid::ProcExtStateEnumEax06`
636+ //
637+ // level 5
638+ let mut kregs_state = ExtendedState :: empty ( ) ;
639+ kregs_state. set_size ( 0x040 ) ;
640+ kregs_state. set_offset ( 0x340 ) ;
641+ leaves. push ( Some ( kregs_state. into_leaf ( ) ) ) ;
642+ // level 6
643+ let mut zmmhi_state = ExtendedState :: empty ( ) ;
644+ zmmhi_state. set_size ( 0x200 ) ;
645+ zmmhi_state. set_offset ( 0x380 ) ;
646+ leaves. push ( Some ( zmmhi_state. into_leaf ( ) ) ) ;
647+ // level 7
648+ let mut zmmhi16_state = ExtendedState :: empty ( ) ;
649+ zmmhi16_state. set_size ( 0x400 ) ;
650+ zmmhi16_state. set_offset ( 0x580 ) ;
651+ leaves. push ( Some ( zmmhi16_state. into_leaf ( ) ) ) ;
652+
653+ cpuid. set_extended_state_info ( Some ( & leaves[ ..] ) ) . expect ( "can set leaf Dh" ) ;
582654
583655 let mut leaf = cpuid
584656 . get_extended_processor_and_feature_identifiers ( )
585657 . expect ( "baseline Milan defines leaf 8000_0001" ) ;
586658 // RDTSCP requires some bhyve and Propolis work to support, so it is masked
587659 // off for now.
588660 leaf. set_rdtscp ( false ) ;
589- cpuid. set_extended_processor_and_feature_identifiers ( Some ( leaf) )
661+ cpuid
662+ . set_extended_processor_and_feature_identifiers ( Some ( leaf) )
590663 . expect ( "can set leaf 8000_0001h" ) ;
591664
592665 cpuid
@@ -602,10 +675,57 @@ pub fn turin_v1() -> CpuIdDump {
602675 // hiding this instruction.
603676 leaf. set_wbnoinvd ( false ) ;
604677
678+ // "Processor is not vulnerable to Branch Type Confusion"
679+ // This is 1 for all Turin processors and does not require particular MSR
680+ // settings or hypervisor support, so pass it along.
681+ leaf. set_btc_no ( true ) ;
682+
683+ // BSFD, SSBD, STIBP, and IBRS, are all supported on Turin, but guests
684+ // are not yet allowed to access SPEC_CTRL to enable (or confirm they are
685+ // enabled).
686+ leaf. set_psfd ( false ) ;
687+ leaf. set_ssbd ( false ) ;
688+ leaf. set_stibp ( false ) ;
689+ leaf. set_ibrs ( false ) ;
690+
605691 cpuid
606692 . set_processor_capacity_feature_info ( Some ( leaf) )
607693 . expect ( "can set leaf 8000_0008h" ) ;
608694
695+ let mut leaf = cpuid
696+ . get_performance_optimization_info ( )
697+ . expect ( "baseline Milan defines 8000_001Ah" ) ;
698+ leaf. set_fp256 ( false ) ;
699+ leaf. set_fp512 ( true ) ;
700+ cpuid
701+ . set_performance_optimization_info ( Some ( leaf) )
702+ . expect ( "can set leaf 8000_001Ah" ) ;
703+
704+ let mut leaf = cpuid
705+ . get_extended_feature_identification_2 ( )
706+ . expect ( "can get leaf 8000_0021h" ) ;
707+
708+ // FP512 downgrade is configurable via MSR, but the MSR is not made
709+ // available to guests. The other bits are present on all Turin processors.
710+ leaf. set_fp512_downgrade ( false ) ;
711+ leaf. set_fast_rep_scasb ( true ) ;
712+ leaf. set_epsf ( true ) ;
713+ leaf. set_opcode_0f_017_reclaim ( true ) ;
714+ leaf. set_amd_ermsb ( true ) ;
715+ leaf. set_fast_short_repe_cmpsb ( true ) ;
716+ leaf. set_fast_short_rep_stosb ( true ) ;
717+ // The EFER write is permitted in bhyve, so this *should* work?
718+ leaf. set_automatic_ibrs ( true ) ;
719+ // The EFER write is permitted in bhyve, so this *should* work? But the
720+ // forward utility of this bit is not as clear, so hide it.
721+ leaf. set_upper_address_ignore ( false ) ;
722+ // Architectural behavior, so we should pass this through.
723+ leaf. set_fs_gs_base_write_not_serializing ( true ) ;
724+
725+ cpuid
726+ . set_extended_feature_identification_2 ( Some ( leaf) )
727+ . expect ( "can set leaf 8000_0021h" ) ;
728+
609729 // Cache topology leaves are otherwise left zeroed; if we can avoid getting
610730 // into it, let's try!
611731
@@ -817,7 +937,7 @@ pub fn dump_to_cpuid_entries(dump: CpuIdDump) -> Vec<CpuidEntry> {
817937#[ cfg( test) ]
818938mod test {
819939 use crate :: app:: instance_platform:: cpu_platform:: {
820- dump_to_cpuid_entries, milan_rfd314,
940+ dump_to_cpuid_entries, milan_rfd314, turin_v1 ,
821941 } ;
822942 use raw_cpuid:: {
823943 CpuId , CpuIdReader , CpuIdResult , CpuIdWriter , L1CacheTlbInfo ,
@@ -910,6 +1030,77 @@ mod test {
9101030 cpuid_leaf ! ( 0x80000021 , 0x00000045 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
9111031 ] ;
9121032
1033+ // This CPUID leaf blob is some small tweaks on top of the "ideal Milan",
1034+ // maintaining some details that are disabled due to needed bhyve support
1035+ // and including Turin-specific features as supported and relevant to
1036+ // guests.
1037+ const TURIN_V1_CPUID : [ CpuidEntry ; 26 ] = [
1038+ cpuid_leaf ! ( 0x0 , 0x0000000D , 0x68747541 , 0x444D4163 , 0x69746E65 ) ,
1039+ cpuid_leaf ! ( 0x1 , 0x00A00F11 , 0x00000800 , 0xF6D83203 , 0x078BFBFF ) ,
1040+ cpuid_leaf ! ( 0x5 , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
1041+ cpuid_leaf ! ( 0x6 , 0x00000004 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
1042+ cpuid_subleaf ! (
1043+ 0x7 , 0x0 , 0x00000001 , 0xF1BF03A9 , 0x00005F42 , 0x00000110
1044+ ) ,
1045+ cpuid_subleaf ! (
1046+ 0x7 , 0x1 , 0x00000030 , 0x00000000 , 0x00000000 , 0x00000000
1047+ ) ,
1048+ cpuid_subleaf ! (
1049+ 0xD , 0x0 , 0x000000E7 , 0x00000980 , 0x00000980 , 0x00000000
1050+ ) ,
1051+ cpuid_subleaf ! (
1052+ 0xD , 0x1 , 0x00000007 , 0x00000980 , 0x00000000 , 0x00000000
1053+ ) ,
1054+ cpuid_subleaf ! (
1055+ 0xD , 0x2 , 0x00000100 , 0x00000240 , 0x00000000 , 0x00000000
1056+ ) ,
1057+ /*
1058+ * subleaves 3 and 4 are all-zero
1059+ */
1060+ cpuid_subleaf ! (
1061+ 0xD , 0x5 , 0x00000040 , 0x00000340 , 0x00000000 , 0x00000000
1062+ ) ,
1063+ cpuid_subleaf ! (
1064+ 0xD , 0x6 , 0x00000200 , 0x00000380 , 0x00000000 , 0x00000000
1065+ ) ,
1066+ cpuid_subleaf ! (
1067+ 0xD , 0x7 , 0x00000400 , 0x00000580 , 0x00000000 , 0x00000000
1068+ ) ,
1069+ cpuid_leaf ! ( 0x80000000 , 0x80000021 , 0x68747541 , 0x444D4163 , 0x69746E65 ) ,
1070+ cpuid_leaf ! ( 0x80000001 , 0x00A00F11 , 0x40000000 , 0x44C001F1 , 0x25D3FBFF ) ,
1071+ cpuid_leaf ! ( 0x80000002 , 0x6469784F , 0x69562065 , 0x61757472 , 0x7554206C ) ,
1072+ cpuid_leaf ! ( 0x80000003 , 0x2D6E6972 , 0x656B696C , 0x6F725020 , 0x73736563 ) ,
1073+ cpuid_leaf ! ( 0x80000004 , 0x2020726F , 0x20202020 , 0x20202020 , 0x00202020 ) ,
1074+ cpuid_leaf ! ( 0x80000007 , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000100 ) ,
1075+ cpuid_leaf ! ( 0x80000008 , 0x00003030 , 0x20000005 , 0x00000000 , 0x00000000 ) ,
1076+ cpuid_leaf ! ( 0x8000000A , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
1077+ cpuid_leaf ! ( 0x8000001A , 0x0000000A , 0x00000000 , 0x00000000 , 0x00000000 ) ,
1078+ cpuid_leaf ! ( 0x8000001B , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
1079+ cpuid_leaf ! ( 0x8000001C , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
1080+ cpuid_leaf ! ( 0x8000001E , 0x00000000 , 0x00000100 , 0x00000000 , 0x00000000 ) ,
1081+ cpuid_leaf ! ( 0x8000001F , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
1082+ cpuid_leaf ! ( 0x80000021 , 0x000D8D47 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
1083+ ] ;
1084+
1085+ // Test that Turin V1 matches the predetermined CPUID leaves written above
1086+ // (e.g. that the collection of builders behind `turin_v1` produce this
1087+ // profile as used for testing and elsewhere).
1088+ //
1089+ // This is largely "baseline Milan" with Turin-specific additions.
1090+ #[ test]
1091+ fn turin_v1_is_as_described ( ) {
1092+ let computed = dump_to_cpuid_entries ( turin_v1 ( ) ) ;
1093+
1094+ for ( l, r) in TURIN_V1_CPUID . iter ( ) . zip ( computed. as_slice ( ) . iter ( ) ) {
1095+ eprintln ! ( "comparing {:#08x}.{:?}" , l. leaf, l. subleaf) ;
1096+ assert_eq ! (
1097+ l, r,
1098+ "leaf 0x{:08x} (subleaf? {:?}) did not match" ,
1099+ l. leaf, l. subleaf
1100+ ) ;
1101+ }
1102+ }
1103+
9131104 // Test that the initial RFD 314 definition matches what we compute as the
9141105 // CPUID profile with that configuration in `milan_rfd314()`.
9151106 #[ test]
0 commit comments