@@ -30,6 +30,9 @@ pub struct XState {
30
30
guest_xcr0 : u64 ,
31
31
host_xss : u64 ,
32
32
guest_xss : u64 ,
33
+
34
+ xsave_available : bool ,
35
+ xsaves_available : bool ,
33
36
}
34
37
35
38
#[ derive( PartialEq , Eq , Debug ) ]
@@ -43,20 +46,91 @@ pub enum VmCpuMode {
43
46
impl XState {
44
47
/// Create a new [`XState`] instance with current host state
45
48
fn new ( ) -> Self {
46
- let xcr0 = unsafe { xcr0_read ( ) . bits ( ) } ;
47
- let xss = Msr :: IA32_XSS . read ( ) ;
49
+ // Check if XSAVE is available
50
+ let xsave_available = Self :: xsave_available ( ) ;
51
+ // Check if XSAVES and XRSTORS (as well as IA32_XSS) are available
52
+ let xsaves_available = if xsave_available {
53
+ Self :: xsaves_available ( )
54
+ } else {
55
+ false
56
+ } ;
57
+
58
+ // Read XCR0 iff XSAVE is available
59
+ let xcr0 = if xsave_available {
60
+ unsafe { xcr0_read ( ) . bits ( ) }
61
+ } else {
62
+ 0
63
+ } ;
64
+ // Read IA32_XSS iff XSAVES is available
65
+ let xss = if xsaves_available {
66
+ Msr :: IA32_XSS . read ( )
67
+ } else {
68
+ 0
69
+ } ;
48
70
49
71
Self {
50
72
host_xcr0 : xcr0,
51
73
guest_xcr0 : xcr0,
52
74
host_xss : xss,
53
75
guest_xss : xss,
76
+ xsave_available,
77
+ xsaves_available,
54
78
}
55
79
}
56
80
57
- /// Enables extended processor state management instructions, including XGETBV and XSAVE.
81
+ /// Enable extended processor state management instructions, including XGETBV and XSAVE.
58
82
pub fn enable_xsave ( ) {
59
- unsafe { Cr4 :: write ( Cr4 :: read ( ) | Cr4Flags :: OSXSAVE ) } ;
83
+ if Self :: xsave_available ( ) {
84
+ unsafe { Cr4 :: write ( Cr4 :: read ( ) | Cr4Flags :: OSXSAVE ) } ;
85
+ }
86
+ }
87
+
88
+ /// Check if XSAVE is available on the current CPU.
89
+ pub fn xsave_available ( ) -> bool {
90
+ let cpuid = CpuId :: new ( ) ;
91
+ cpuid
92
+ . get_feature_info ( )
93
+ . map ( |f| f. has_xsave ( ) )
94
+ . unwrap_or ( false )
95
+ }
96
+
97
+ /// Check if XSAVES and XRSTORS (as well as IA32_XSS) are available on the current CPU.
98
+ pub fn xsaves_available ( ) -> bool {
99
+ let cpuid = CpuId :: new ( ) ;
100
+ cpuid
101
+ . get_extended_state_info ( )
102
+ . map ( |f| f. has_xsaves_xrstors ( ) )
103
+ . unwrap_or ( false )
104
+ }
105
+
106
+ /// Save the current host XCR0 and IA32_XSS values and load the guest values.
107
+ pub fn switch_to_guest ( & mut self ) {
108
+ unsafe {
109
+ if self . xsave_available {
110
+ self . host_xcr0 = xcr0_read ( ) . bits ( ) ;
111
+ xcr0_write ( Xcr0 :: from_bits_unchecked ( self . guest_xcr0 ) ) ;
112
+
113
+ if self . xsaves_available {
114
+ self . host_xss = Msr :: IA32_XSS . read ( ) ;
115
+ Msr :: IA32_XSS . write ( self . guest_xss ) ;
116
+ }
117
+ }
118
+ }
119
+ }
120
+
121
+ /// Save the current guest XCR0 and IA32_XSS values and load the host values.
122
+ pub fn switch_to_host ( & mut self ) {
123
+ unsafe {
124
+ if self . xsave_available {
125
+ self . guest_xcr0 = xcr0_read ( ) . bits ( ) ;
126
+ xcr0_write ( Xcr0 :: from_bits_unchecked ( self . host_xcr0 ) ) ;
127
+
128
+ if self . xsaves_available {
129
+ self . guest_xss = Msr :: IA32_XSS . read ( ) ;
130
+ Msr :: IA32_XSS . write ( self . host_xss ) ;
131
+ }
132
+ }
133
+ }
60
134
}
61
135
}
62
136
@@ -1008,17 +1082,11 @@ impl<H: AxVCpuHal> VmxVcpu<H> {
1008
1082
}
1009
1083
1010
1084
fn load_guest_xstate ( & mut self ) {
1011
- unsafe {
1012
- xcr0_write ( Xcr0 :: from_bits_unchecked ( self . xstate . guest_xcr0 ) ) ;
1013
- Msr :: IA32_XSS . write ( self . xstate . guest_xss ) ;
1014
- }
1085
+ self . xstate . switch_to_guest ( ) ;
1015
1086
}
1016
1087
1017
1088
fn load_host_xstate ( & mut self ) {
1018
- unsafe {
1019
- xcr0_write ( Xcr0 :: from_bits_unchecked ( self . xstate . host_xcr0 ) ) ;
1020
- Msr :: IA32_XSS . write ( self . xstate . host_xss ) ;
1021
- }
1089
+ self . xstate . switch_to_host ( ) ;
1022
1090
}
1023
1091
}
1024
1092
0 commit comments