@@ -19,9 +19,13 @@ use hvdef::HvError;
19
19
use hvdef:: HvMapGpaFlags ;
20
20
use hvdef:: HvRegisterVsmPartitionConfig ;
21
21
use hvdef:: HvResult ;
22
+ use hvdef:: HvVtlEntryReason ;
23
+ use hvdef:: HvX64RegisterName ;
22
24
use hvdef:: Vtl ;
23
25
use std:: iter:: zip;
24
26
use virt:: io:: CpuIo ;
27
+ use virt:: vp:: AccessVpState ;
28
+ use virt:: Processor ;
25
29
use zerocopy:: FromZeroes ;
26
30
27
31
impl < T : CpuIo , B : HardwareIsolatedBacking > UhHypercallHandler < ' _ , ' _ , T , B > {
@@ -200,7 +204,7 @@ impl<T: CpuIo, B: HardwareIsolatedBacking> UhHypercallHandler<'_, '_, T, B> {
200
204
* target_vp. hv_start_enable_vtl_vp [ vtl] . lock ( ) = Some ( Box :: new ( * vp_context) ) ;
201
205
target_vp. wake ( vtl, WakeReason :: HV_START_ENABLE_VP_VTL ) ;
202
206
203
- tracing:: debug!( "enabled vtl 1 on vp {}" , vp_index ) ;
207
+ tracing:: debug!( vp_index , "enabled vtl 1 on vp" ) ;
204
208
205
209
Ok ( ( ) )
206
210
}
@@ -238,18 +242,29 @@ impl<T: CpuIo, B: HardwareIsolatedBacking> UhHypercallHandler<'_, '_, T, B> {
238
242
vtl : GuestVtl ,
239
243
) -> HvResult < hvdef:: HvRegisterValue > {
240
244
match name. into ( ) {
241
- hvdef :: HvX64RegisterName :: VsmCodePageOffsets => Ok ( u64:: from (
245
+ HvX64RegisterName :: VsmCodePageOffsets => Ok ( u64:: from (
242
246
self . vp . hv [ vtl]
243
247
. as_ref ( )
244
248
. expect ( "hv emulator exists for cvm" )
245
249
. vsm_code_page_offsets ( true ) ,
246
250
)
247
251
. into ( ) ) ,
248
- hvdef :: HvX64RegisterName :: VsmCapabilities => Ok ( u64:: from (
252
+ HvX64RegisterName :: VsmCapabilities => Ok ( u64:: from (
249
253
hvdef:: HvRegisterVsmCapabilities :: new ( ) . with_deny_lower_vtl_startup ( true ) ,
250
254
)
251
255
. into ( ) ) ,
252
- _ => Err ( HvError :: InvalidParameter ) ,
256
+ HvX64RegisterName :: VpAssistPage => Ok ( self . vp . hv [ vtl]
257
+ . as_ref ( )
258
+ . expect ( "hv emulator exists for cvm" )
259
+ . vp_assist_page ( )
260
+ . into ( ) ) ,
261
+ _ => {
262
+ tracing:: error!(
263
+ ?name,
264
+ "guest invoked getvpregister with unsupported register"
265
+ ) ;
266
+ Err ( HvError :: InvalidParameter )
267
+ }
253
268
}
254
269
}
255
270
@@ -329,32 +344,6 @@ impl<T: CpuIo, B: HardwareIsolatedBacking> UhHypercallHandler<'_, '_, T, B> {
329
344
// TODO should we check the all_virtual_address_spaces flag? we don't check this flag or the address space input arg anywhere in the hcl
330
345
Ok ( ( ) )
331
346
}
332
-
333
- pub fn hcvm_is_vtl_call_allowed ( & self ) -> bool {
334
- tracing:: trace!( "checking if vtl call is allowed" ) ;
335
-
336
- // Only allowed from VTL 0
337
- if self . intercepted_vtl != GuestVtl :: Vtl0 {
338
- false
339
- } else if !* self . vp . inner . hcvm_vtl1_enabled . lock ( ) {
340
- // VTL 1 must be enabled on the vp
341
- false
342
- } else {
343
- true
344
- }
345
- }
346
-
347
- pub fn hcvm_vtl_call ( & mut self ) {
348
- tracing:: trace!( "handling vtl call" ) ;
349
-
350
- self . vp . switch_vtl ( self . intercepted_vtl , GuestVtl :: Vtl1 ) ;
351
- self . vp . backing . cvm_state_mut ( ) . exit_vtl = GuestVtl :: Vtl1 ;
352
-
353
- // TODO GUEST_VSM: Force reevaluation of the VTL 1 APIC in case delivery of
354
- // low-priority interrupts was suppressed while in VTL 0.
355
-
356
- // TODO GUEST_VSM: Track which VTLs are runnable and mark VTL as runnable
357
- }
358
347
}
359
348
360
349
impl < T , B : HardwareIsolatedBacking > hv1_hypercall:: SetVpRegisters
@@ -380,20 +369,112 @@ impl<T, B: HardwareIsolatedBacking> hv1_hypercall::SetVpRegisters
380
369
. map_err ( |_| ( HvError :: InvalidParameter , 0 ) ) ?;
381
370
382
371
for ( i, reg) in registers. iter ( ) . enumerate ( ) {
383
- if reg. name == hvdef:: HvX64RegisterName :: VsmPartitionConfig . into ( ) {
384
- let value = HvRegisterVsmPartitionConfig :: from ( reg. value . as_u64 ( ) ) ;
385
- self . vp
386
- . set_vsm_partition_config ( value, target_vtl)
387
- . map_err ( |e| ( e, i) ) ?;
388
- } else {
389
- return Err ( ( HvError :: InvalidParameter , i) ) ;
372
+ match HvX64RegisterName :: from ( reg. name ) {
373
+ HvX64RegisterName :: VsmPartitionConfig => {
374
+ self . vp
375
+ . set_vsm_partition_config (
376
+ HvRegisterVsmPartitionConfig :: from ( reg. value . as_u64 ( ) ) ,
377
+ target_vtl,
378
+ )
379
+ . map_err ( |e| ( e, i) ) ?;
380
+ }
381
+ HvX64RegisterName :: VpAssistPage => {
382
+ self . vp . hv [ target_vtl]
383
+ . as_mut ( )
384
+ . expect ( "has hv emulator" )
385
+ . msr_write ( hvdef:: HV_X64_MSR_VP_ASSIST_PAGE , reg. value . as_u64 ( ) )
386
+ . map_err ( |_| ( HvError :: InvalidRegisterValue , 0 ) ) ?;
387
+ }
388
+ _ => {
389
+ tracing:: error!(
390
+ ?reg,
391
+ "guest invoked SetVpRegisters with unsupported register"
392
+ ) ;
393
+ return Err ( ( HvError :: InvalidParameter , i) ) ;
394
+ }
390
395
}
391
396
}
392
397
393
398
Ok ( ( ) )
394
399
}
395
400
}
396
401
402
+ impl < T , B : HardwareIsolatedBacking > hv1_hypercall:: VtlCall for UhHypercallHandler < ' _ , ' _ , T , B > {
403
+ fn is_vtl_call_allowed ( & self ) -> bool {
404
+ tracing:: trace!( "checking if vtl call is allowed" ) ;
405
+
406
+ // Only allowed from VTL 0
407
+ if self . intercepted_vtl != GuestVtl :: Vtl0 {
408
+ false
409
+ } else if !* self . vp . inner . hcvm_vtl1_enabled . lock ( ) {
410
+ // VTL 1 must be enabled on the vp
411
+ false
412
+ } else {
413
+ true
414
+ }
415
+ }
416
+
417
+ fn vtl_call ( & mut self ) {
418
+ tracing:: trace!( "handling vtl call" ) ;
419
+
420
+ B :: switch_vtl_state ( self . vp , self . intercepted_vtl , GuestVtl :: Vtl1 ) ;
421
+ self . vp . backing . cvm_state_mut ( ) . exit_vtl = GuestVtl :: Vtl1 ;
422
+
423
+ // TODO GUEST VSM: reevaluate if the return reason should be set here or
424
+ // during VTL 2 exit handling
425
+ self . vp . hv [ GuestVtl :: Vtl1 ]
426
+ . as_ref ( )
427
+ . unwrap ( )
428
+ . set_return_reason ( HvVtlEntryReason :: VTL_CALL )
429
+ . expect ( "setting return reason cannot fail" ) ;
430
+
431
+ // TODO GUEST_VSM: Force reevaluation of the VTL 1 APIC in case delivery of
432
+ // low-priority interrupts was suppressed while in VTL 0.
433
+
434
+ // TODO GUEST_VSM: Track which VTLs are runnable and mark VTL as runnable
435
+ }
436
+ }
437
+
438
+ impl < T , B : HardwareIsolatedBacking > hv1_hypercall:: VtlReturn for UhHypercallHandler < ' _ , ' _ , T , B > {
439
+ fn is_vtl_return_allowed ( & self ) -> bool {
440
+ tracing:: trace!( "checking if vtl return is allowed" ) ;
441
+
442
+ // Only allowed from VTL 1
443
+ self . intercepted_vtl != GuestVtl :: Vtl0
444
+ }
445
+
446
+ fn vtl_return ( & mut self , fast : bool ) {
447
+ tracing:: trace!( "handling vtl return" ) ;
448
+
449
+ self . vp . unlock_tlb_lock ( Vtl :: Vtl1 ) ;
450
+
451
+ B :: switch_vtl_state ( self . vp , self . intercepted_vtl , GuestVtl :: Vtl0 ) ;
452
+ self . vp . backing . cvm_state_mut ( ) . exit_vtl = GuestVtl :: Vtl0 ;
453
+
454
+ // TODO CVM GUEST_VSM:
455
+ // - rewind interrupts
456
+ // - reset VINA
457
+
458
+ if !fast {
459
+ let [ rax, rcx] = self . vp . hv [ GuestVtl :: Vtl1 ]
460
+ . as_ref ( )
461
+ . unwrap ( )
462
+ . return_registers ( )
463
+ . expect ( "getting return registers shouldn't fail" ) ;
464
+ let mut vp_state = self . vp . access_state ( Vtl :: Vtl0 ) ;
465
+ let mut registers = vp_state
466
+ . registers ( )
467
+ . expect ( "getting registers shouldn't fail" ) ;
468
+ registers. rax = rax;
469
+ registers. rcx = rcx;
470
+
471
+ vp_state
472
+ . set_registers ( & registers)
473
+ . expect ( "setting registers shouldn't fail" ) ;
474
+ }
475
+ }
476
+ }
477
+
397
478
impl < B : HardwareIsolatedBacking > UhProcessor < ' _ , B > {
398
479
fn set_vsm_partition_config (
399
480
& mut self ,
0 commit comments