@@ -1138,7 +1138,7 @@ impl UhProcessor<'_, TdxBacked> {
1138
1138
}
1139
1139
1140
1140
if self . backing . vtls [ vtl] . processor_controls != new_processor_controls {
1141
- tracing:: debug !( ?new_processor_controls, ?vtl, "requesting window change" ) ;
1141
+ tracing:: trace !( ?new_processor_controls, ?vtl, "requesting window change" ) ;
1142
1142
self . runner . write_vmcs32 (
1143
1143
vtl,
1144
1144
VmcsField :: VMX_VMCS_PROCESSOR_CONTROLS ,
@@ -2071,10 +2071,10 @@ impl UhProcessor<'_, TdxBacked> {
2071
2071
HvX64RegisterName :: Gdtr
2072
2072
}
2073
2073
} ;
2074
- // We only support fowarding intercepts for descriptor table writes today.
2075
- if ( info. instruction ( ) . is_write ( )
2074
+ // We only support fowarding intercepts for descriptor table loads today.
2075
+ if ( info. instruction ( ) . is_load ( )
2076
2076
&& !self . cvm_try_protect_secure_register_write ( intercepted_vtl, reg, 0 ) )
2077
- || !info. instruction ( ) . is_write ( )
2077
+ || !info. instruction ( ) . is_load ( )
2078
2078
{
2079
2079
self . emulate_gdtr_or_idtr ( intercepted_vtl, dev) . await ?;
2080
2080
}
@@ -2091,10 +2091,10 @@ impl UhProcessor<'_, TdxBacked> {
2091
2091
}
2092
2092
LdtrOrTrInstruction :: Str | LdtrOrTrInstruction :: Ltr => HvX64RegisterName :: Tr ,
2093
2093
} ;
2094
- // We only support fowarding intercepts for descriptor table writes today.
2095
- if ( info. instruction ( ) . is_write ( )
2094
+ // We only support fowarding intercepts for descriptor table loads today.
2095
+ if ( info. instruction ( ) . is_load ( )
2096
2096
&& !self . cvm_try_protect_secure_register_write ( intercepted_vtl, reg, 0 ) )
2097
- || !info. instruction ( ) . is_write ( )
2097
+ || !info. instruction ( ) . is_load ( )
2098
2098
{
2099
2099
self . emulate_ldtr_or_tr ( intercepted_vtl, dev) . await ?;
2100
2100
}
@@ -2752,7 +2752,9 @@ impl<T: CpuIo> X86EmulatorSupport for UhEmulationState<'_, '_, T, TdxBacked> {
2752
2752
let exit_info = TdxExit ( self . vp . runner . tdx_vp_enter_exit_info ( ) ) ;
2753
2753
let ept_info = VmxEptExitQualification :: from ( exit_info. qualification ( ) ) ;
2754
2754
2755
- if ept_info. gva_valid ( ) {
2755
+ if exit_info. code ( ) . vmx_exit ( ) . basic_reason ( ) == VmxExitBasic :: EPT_VIOLATION
2756
+ && ept_info. gva_valid ( )
2757
+ {
2756
2758
Some ( virt_support_x86emu:: emulate:: InitialTranslation {
2757
2759
gva : exit_info. gla ( ) ,
2758
2760
gpa : exit_info. gpa ( ) ,
@@ -3061,44 +3063,26 @@ impl UhProcessor<'_, TdxBacked> {
3061
3063
VmxExitBasic :: GDTR_OR_IDTR
3062
3064
) ;
3063
3065
let instr_info = GdtrOrIdtrInstructionInfo :: from ( exit_info. instr_info ( ) . info ( ) ) ;
3064
- let gps = self . runner . tdx_enter_guest_gps ( ) ;
3065
3066
3066
- // Check if read instructions are blocked by UMIP.
3067
- if !instr_info. instruction ( ) . is_write ( )
3068
- && exit_info. cpl ( ) > 0
3069
- && self . read_cr4 ( vtl) & X64_CR4_UMIP != 0
3067
+ // Check if load instructions are executed outside of kernel mode.
3068
+ // Check if store instructions are blocked by UMIP.
3069
+ if ( instr_info. instruction ( ) . is_load ( ) && exit_info. cpl ( ) != 0 )
3070
+ || ( !instr_info. instruction ( ) . is_load ( )
3071
+ && exit_info. cpl ( ) > 0
3072
+ && self . read_cr4 ( vtl) & X64_CR4_UMIP != 0 )
3070
3073
{
3071
3074
self . inject_gpf ( vtl) ;
3072
3075
return Ok ( ( ) ) ;
3073
3076
}
3074
3077
3075
- // Displacement is stored in the qualification field for these instructions.
3076
- let mut gva = exit_info. qualification ( ) ;
3077
- if !instr_info. base_register_invalid ( ) {
3078
- gva += gps[ instr_info. base_register ( ) as usize ] ;
3079
- }
3080
- if !instr_info. index_register_invalid ( ) {
3081
- gva += gps[ instr_info. index_register ( ) as usize ] << instr_info. scaling ( ) ;
3082
- }
3083
- match instr_info. address_size ( ) {
3084
- // 16-bit address size
3085
- 0 => gva &= 0xFFFF ,
3086
- // 32-bit address size
3087
- 1 => gva &= 0xFFFFFFFF ,
3088
- // 64-bit address size
3089
- 2 => { }
3090
- _ => unreachable ! ( ) ,
3091
- }
3092
-
3093
- let segment = match instr_info. segment_register ( ) {
3094
- 0 => Segment :: ES ,
3095
- 1 => Segment :: CS ,
3096
- 2 => Segment :: SS ,
3097
- 3 => Segment :: DS ,
3098
- 4 => Segment :: FS ,
3099
- 5 => Segment :: GS ,
3100
- _ => unreachable ! ( ) ,
3101
- } ;
3078
+ let ( gva, segment) = self . compute_gva_for_table_access_emulation (
3079
+ exit_info. qualification ( ) ,
3080
+ ( !instr_info. base_register_invalid ( ) ) . then_some ( instr_info. base_register ( ) ) ,
3081
+ ( !instr_info. index_register_invalid ( ) ) . then_some ( instr_info. index_register ( ) ) ,
3082
+ instr_info. scaling ( ) ,
3083
+ instr_info. address_size ( ) ,
3084
+ instr_info. segment_register ( ) ,
3085
+ ) ;
3102
3086
3103
3087
let gm = & self . partition . gm [ vtl] ;
3104
3088
let interruption_pending = self . backing . vtls [ vtl] . interruption_information . valid ( ) ;
@@ -3176,10 +3160,167 @@ impl UhProcessor<'_, TdxBacked> {
3176
3160
3177
3161
async fn emulate_ldtr_or_tr (
3178
3162
& mut self ,
3179
- _vtl : GuestVtl ,
3180
- _dev : & impl CpuIo ,
3163
+ vtl : GuestVtl ,
3164
+ dev : & impl CpuIo ,
3181
3165
) -> Result < ( ) , VpHaltReason < UhRunVpError > > {
3182
- todo ! ( )
3166
+ let exit_info = TdxExit ( self . runner . tdx_vp_enter_exit_info ( ) ) ;
3167
+ assert_eq ! (
3168
+ exit_info. code( ) . vmx_exit( ) . basic_reason( ) ,
3169
+ VmxExitBasic :: LDTR_OR_TR
3170
+ ) ;
3171
+ let instr_info = LdtrOrTrInstructionInfo :: from ( exit_info. instr_info ( ) . info ( ) ) ;
3172
+
3173
+ // Check if load instructions are executed outside of kernel mode.
3174
+ // Check if store instructions are blocked by UMIP.
3175
+ if ( instr_info. instruction ( ) . is_load ( ) && exit_info. cpl ( ) != 0 )
3176
+ || ( !instr_info. instruction ( ) . is_load ( )
3177
+ && exit_info. cpl ( ) > 0
3178
+ && self . read_cr4 ( vtl) & X64_CR4_UMIP != 0 )
3179
+ {
3180
+ self . inject_gpf ( vtl) ;
3181
+ return Ok ( ( ) ) ;
3182
+ }
3183
+
3184
+ let gm = & self . partition . gm [ vtl] ;
3185
+ let interruption_pending = self . backing . vtls [ vtl] . interruption_information . valid ( ) ;
3186
+
3187
+ match instr_info. instruction ( ) {
3188
+ LdtrOrTrInstruction :: Sldt | LdtrOrTrInstruction :: Str => {
3189
+ let value = self . runner . read_vmcs16 (
3190
+ vtl,
3191
+ if matches ! ( instr_info. instruction( ) , LdtrOrTrInstruction :: Sldt ) {
3192
+ TdxSegmentReg :: Ldtr
3193
+ } else {
3194
+ TdxSegmentReg :: Tr
3195
+ }
3196
+ . selector ( ) ,
3197
+ ) ;
3198
+
3199
+ if instr_info. memory_or_register ( ) {
3200
+ let gps = self . runner . tdx_enter_guest_gps_mut ( ) ;
3201
+ gps[ instr_info. register_1 ( ) as usize ] = value. into ( ) ;
3202
+ } else {
3203
+ let ( gva, segment) = self . compute_gva_for_table_access_emulation (
3204
+ exit_info. qualification ( ) ,
3205
+ ( !instr_info. base_register_invalid ( ) ) . then_some ( instr_info. base_register ( ) ) ,
3206
+ ( !instr_info. index_register_invalid ( ) )
3207
+ . then_some ( instr_info. index_register ( ) ) ,
3208
+ instr_info. scaling ( ) ,
3209
+ instr_info. address_size ( ) ,
3210
+ instr_info. segment_register ( ) ,
3211
+ ) ;
3212
+ let mut emulation_state = UhEmulationState {
3213
+ vp : & mut * self ,
3214
+ interruption_pending,
3215
+ devices : dev,
3216
+ vtl,
3217
+ cache : TdxEmulationCache :: default ( ) ,
3218
+ } ;
3219
+ emulate_insn_memory_op (
3220
+ & mut emulation_state,
3221
+ gm,
3222
+ dev,
3223
+ gva,
3224
+ segment,
3225
+ x86emu:: AlignmentMode :: Standard ,
3226
+ EmulatedMemoryOperation :: Write ( & value. to_le_bytes ( ) ) ,
3227
+ )
3228
+ . await ?;
3229
+ }
3230
+ }
3231
+
3232
+ LdtrOrTrInstruction :: Lldt | LdtrOrTrInstruction :: Ltr => {
3233
+ let value = if instr_info. memory_or_register ( ) {
3234
+ let gps = self . runner . tdx_enter_guest_gps ( ) ;
3235
+ gps[ instr_info. register_1 ( ) as usize ] as u16
3236
+ } else {
3237
+ let ( gva, segment) = self . compute_gva_for_table_access_emulation (
3238
+ exit_info. qualification ( ) ,
3239
+ ( !instr_info. base_register_invalid ( ) ) . then_some ( instr_info. base_register ( ) ) ,
3240
+ ( !instr_info. index_register_invalid ( ) )
3241
+ . then_some ( instr_info. index_register ( ) ) ,
3242
+ instr_info. scaling ( ) ,
3243
+ instr_info. address_size ( ) ,
3244
+ instr_info. segment_register ( ) ,
3245
+ ) ;
3246
+ let mut emulation_state = UhEmulationState {
3247
+ vp : & mut * self ,
3248
+ interruption_pending,
3249
+ devices : dev,
3250
+ vtl,
3251
+ cache : TdxEmulationCache :: default ( ) ,
3252
+ } ;
3253
+ let mut buf = [ 0u8 ; 2 ] ;
3254
+ emulate_insn_memory_op (
3255
+ & mut emulation_state,
3256
+ gm,
3257
+ dev,
3258
+ gva,
3259
+ segment,
3260
+ x86emu:: AlignmentMode :: Standard ,
3261
+ EmulatedMemoryOperation :: Read ( & mut buf) ,
3262
+ )
3263
+ . await ?;
3264
+ u16:: from_le_bytes ( buf)
3265
+ } ;
3266
+ self . runner . write_vmcs16 (
3267
+ vtl,
3268
+ if matches ! ( instr_info. instruction( ) , LdtrOrTrInstruction :: Lldt ) {
3269
+ TdxSegmentReg :: Ldtr
3270
+ } else {
3271
+ TdxSegmentReg :: Tr
3272
+ }
3273
+ . selector ( ) ,
3274
+ !0 ,
3275
+ value,
3276
+ ) ;
3277
+ }
3278
+ }
3279
+
3280
+ self . advance_to_next_instruction ( vtl) ;
3281
+ Ok ( ( ) )
3282
+ }
3283
+
3284
+ fn compute_gva_for_table_access_emulation (
3285
+ & self ,
3286
+ qualification : u64 ,
3287
+ base_reg : Option < u8 > ,
3288
+ index_reg : Option < u8 > ,
3289
+ scaling : u8 ,
3290
+ address_size : u8 ,
3291
+ segment_register : u8 ,
3292
+ ) -> ( u64 , Segment ) {
3293
+ let gps = self . runner . tdx_enter_guest_gps ( ) ;
3294
+
3295
+ // Displacement is stored in the qualification field for these instructions.
3296
+ let mut gva = qualification;
3297
+ if let Some ( base_register) = base_reg {
3298
+ gva += gps[ base_register as usize ] ;
3299
+ }
3300
+ if let Some ( index_register) = index_reg {
3301
+ gva += gps[ index_register as usize ] << scaling;
3302
+ }
3303
+ match address_size {
3304
+ // 16-bit address size
3305
+ 0 => gva &= 0xFFFF ,
3306
+ // 32-bit address size
3307
+ 1 => gva &= 0xFFFFFFFF ,
3308
+ // 64-bit address size
3309
+ 2 => { }
3310
+ _ => unreachable ! ( ) ,
3311
+ }
3312
+
3313
+ let segment = match segment_register {
3314
+ 0 => Segment :: ES ,
3315
+ 1 => Segment :: CS ,
3316
+ 2 => Segment :: SS ,
3317
+ 3 => Segment :: DS ,
3318
+ 4 => Segment :: FS ,
3319
+ 5 => Segment :: GS ,
3320
+ _ => unreachable ! ( ) ,
3321
+ } ;
3322
+
3323
+ ( gva, segment)
3183
3324
}
3184
3325
}
3185
3326
0 commit comments