@@ -21,7 +21,7 @@ use std::sync::Arc;
2121use std:: sync:: Mutex ;
2222use std:: sync:: atomic:: { AtomicBool , AtomicU64 , Ordering } ;
2323
24- use kvm_bindings:: { KVM_MEM_READONLY , kvm_fpu, kvm_regs, kvm_userspace_memory_region} ;
24+ use kvm_bindings:: { KVM_MEM_READONLY , kvm_fpu, kvm_regs, kvm_userspace_memory_region, kvm_xcrs } ;
2525use kvm_ioctls:: Cap :: UserMemory ;
2626use kvm_ioctls:: { Kvm , VcpuExit , VcpuFd , VmFd } ;
2727use log:: LevelFilter ;
@@ -37,8 +37,8 @@ use super::handlers::DbgMemAccessHandlerWrapper;
3737use super :: handlers:: { MemAccessHandlerWrapper , OutBHandlerWrapper } ;
3838#[ cfg( feature = "init-paging" ) ]
3939use super :: {
40- CR0_AM , CR0_ET , CR0_MP , CR0_NE , CR0_PE , CR0_PG , CR0_WP , CR4_OSFXSR , CR4_OSXMMEXCPT , CR4_PAE ,
41- EFER_LMA , EFER_LME , EFER_NX , EFER_SCE ,
40+ CR0_AM , CR0_ET , CR0_MP , CR0_NE , CR0_PE , CR0_PG , CR0_WP , CR4_OSFXSR , CR4_OSXMMEXCPT ,
41+ CR4_OSXSAVE , CR4_PAE , EFER_LMA , EFER_LME , EFER_NX , EFER_SCE , XCR0_AVX , XCR0_SSE , XCR0_X87 ,
4242} ;
4343use super :: { HyperlightExit , Hypervisor , InterruptHandle , LinuxInterruptHandle , VirtualCPU } ;
4444#[ cfg( gdb) ]
@@ -336,6 +336,7 @@ impl KVMDriver {
336336 } ) ?;
337337
338338 let mut vcpu_fd = vm_fd. create_vcpu ( 0 ) ?;
339+ Self :: setup_cpuid ( & kvm, & mut vcpu_fd) ?;
339340 Self :: setup_initial_sregs ( & mut vcpu_fd, pml4_addr) ?;
340341
341342 #[ cfg( gdb) ]
@@ -409,7 +410,7 @@ impl KVMDriver {
409410 cfg_if:: cfg_if! {
410411 if #[ cfg( feature = "init-paging" ) ] {
411412 sregs. cr3 = _pml4_addr;
412- sregs. cr4 = CR4_PAE | CR4_OSFXSR | CR4_OSXMMEXCPT ;
413+ sregs. cr4 = CR4_PAE | CR4_OSFXSR | CR4_OSXMMEXCPT | CR4_OSXSAVE ;
413414 sregs. cr0 = CR0_PE | CR0_MP | CR0_ET | CR0_NE | CR0_AM | CR0_PG | CR0_WP ;
414415 sregs. efer = EFER_LME | EFER_LMA | EFER_SCE | EFER_NX ;
415416 sregs. cs. l = 1 ; // required for 64-bit mode
@@ -419,6 +420,120 @@ impl KVMDriver {
419420 }
420421 }
421422 vcpu_fd. set_sregs ( & sregs) ?;
423+
424+ // Setup XCR0 (Extended Control Register 0) to enable SIMD features
425+ // This is required for AVX and other SIMD instruction support
426+ // Only set XCR0 if the init-paging feature is enabled
427+ cfg_if:: cfg_if! {
428+ if #[ cfg( feature = "init-paging" ) ] {
429+ // Create a properly initialized kvm_xcrs structure
430+ let mut xcrs: kvm_xcrs = unsafe { std:: mem:: zeroed( ) } ;
431+
432+ // Set XCR0 to enable x87 FPU (required), SSE, and AVX
433+ // XCR0 bit 0 (x87) must always be set for any XSAVE features
434+ xcrs. xcrs[ 0 ] . xcr = 0 ; // XCR0 register number
435+ xcrs. xcrs[ 0 ] . value = XCR0_X87 | XCR0_SSE | XCR0_AVX ;
436+ xcrs. nr_xcrs = 1 ;
437+
438+ println!( "Setting XCRs: XCR0={:#x}, nr_xcrs={}" , xcrs. xcrs[ 0 ] . value, xcrs. nr_xcrs) ;
439+
440+ match vcpu_fd. set_xcrs( & xcrs) {
441+ Ok ( _) => {
442+ println!( "Successfully set XCR0 to enable SIMD features: {:#x}" , xcrs. xcrs[ 0 ] . value) ;
443+ } ,
444+ Err ( e) => {
445+ println!( "Failed to set XCRs (XCR0) for SIMD support: {:?}" , e) ;
446+ }
447+ }
448+ }
449+ }
450+
451+ Ok ( ( ) )
452+ }
453+
454+ /// Setup the CPUID for the vCPU to enable SIMD features.
455+ /// This is done by just mirroring the host's CPUID in the guest.
456+ #[ instrument( err( Debug ) , skip_all, parent = Span :: current( ) , level = "Trace" ) ]
457+ fn setup_cpuid ( kvm : & Kvm , vcpu_fd : & mut VcpuFd ) -> Result < ( ) > {
458+ // Get the supported CPUID from the host machine
459+ let cpuid = kvm. get_supported_cpuid ( kvm_bindings:: KVM_MAX_CPUID_ENTRIES ) ?;
460+
461+ let entries = cpuid. as_slice ( ) ;
462+
463+ // https://en.wikipedia.org/wiki/CPUID
464+ // sse: EAX=1, EDX bit 25
465+ if !entries
466+ . get ( 1 )
467+ . map ( |entry| entry. edx & ( 1 << 25 ) != 0 )
468+ . unwrap_or ( false )
469+ {
470+ return Err ( new_error ! ( "SSE support not detected on the host machine" ) ) ;
471+ }
472+ // sse2 is EAX=1, EDX bit 26
473+ if !entries
474+ . get ( 1 )
475+ . map ( |entry| entry. edx & ( 1 << 26 ) != 0 )
476+ . unwrap_or ( false )
477+ {
478+ return Err ( new_error ! ( "SSE2 support not detected on the host machine" ) ) ;
479+ }
480+ // sse3 is EAX=1, ECX bit 0
481+ if !entries
482+ . get ( 1 )
483+ . map ( |entry| entry. ecx & ( 1 << 0 ) != 0 )
484+ . unwrap_or ( false )
485+ {
486+ return Err ( new_error ! ( "SSE3 support not detected on the host machine" ) ) ;
487+ }
488+ // ssse3 is EAX=1, ECX bit 9
489+ if !entries
490+ . get ( 1 )
491+ . map ( |entry| entry. ecx & ( 1 << 9 ) != 0 )
492+ . unwrap_or ( false )
493+ {
494+ return Err ( new_error ! ( "SSSE3 support not detected on the host machine" ) ) ;
495+ }
496+ // sse4.1 is EAX=1, ECX bit 19
497+ if !entries
498+ . get ( 1 )
499+ . map ( |entry| entry. ecx & ( 1 << 19 ) != 0 )
500+ . unwrap_or ( false )
501+ {
502+ return Err ( new_error ! (
503+ "SSE4.1 support not detected on the host machine"
504+ ) ) ;
505+ }
506+ // sse4.2 is EAX=1, ECX bit 20
507+ if !entries
508+ . get ( 1 )
509+ . map ( |entry| entry. ecx & ( 1 << 20 ) != 0 )
510+ . unwrap_or ( false )
511+ {
512+ return Err ( new_error ! (
513+ "SSE4.2 support not detected on the host machine"
514+ ) ) ;
515+ }
516+ // avx is EAX=1, ECX bit 28
517+ if !entries
518+ . get ( 1 )
519+ . map ( |entry| entry. ecx & ( 1 << 28 ) != 0 )
520+ . unwrap_or ( false )
521+ {
522+ return Err ( new_error ! ( "AVX support not detected on the host machine" ) ) ;
523+ }
524+ // avx2 is EAX=7, EBX bit 5
525+ if !entries
526+ . get ( 7 )
527+ . map ( |entry| entry. ebx & ( 1 << 5 ) != 0 )
528+ . unwrap_or ( false )
529+ {
530+ return Err ( new_error ! ( "AVX2 support not detected on the host machine" ) ) ;
531+ }
532+
533+ // Set the CPUID for the guest's vCPU to be the same as the host's
534+ vcpu_fd. set_cpuid2 ( & cpuid) ?;
535+ println ! ( "CPUID set successfully for SIMD support" ) ;
536+
422537 Ok ( ( ) )
423538 }
424539}
0 commit comments