@@ -91,6 +91,10 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
91
91
*/
92
92
#define AVIC_MAX_PHYSICAL_ID_COUNT 255
93
93
94
+ #define AVIC_UNACCEL_ACCESS_WRITE_MASK 1
95
+ #define AVIC_UNACCEL_ACCESS_OFFSET_MASK 0xFF0
96
+ #define AVIC_UNACCEL_ACCESS_VECTOR_MASK 0xFFFFFFFF
97
+
94
98
static bool erratum_383_found __read_mostly ;
95
99
96
100
static const u32 host_save_user_msrs [] = {
@@ -176,6 +180,7 @@ struct vcpu_svm {
176
180
/* cached guest cpuid flags for faster access */
177
181
bool nrips_enabled : 1 ;
178
182
183
+ u32 ldr_reg ;
179
184
struct page * avic_backing_page ;
180
185
u64 * avic_physical_id_cache ;
181
186
};
@@ -3492,6 +3497,278 @@ static int mwait_interception(struct vcpu_svm *svm)
3492
3497
return nop_interception (svm );
3493
3498
}
3494
3499
3500
+ enum avic_ipi_failure_cause {
3501
+ AVIC_IPI_FAILURE_INVALID_INT_TYPE ,
3502
+ AVIC_IPI_FAILURE_TARGET_NOT_RUNNING ,
3503
+ AVIC_IPI_FAILURE_INVALID_TARGET ,
3504
+ AVIC_IPI_FAILURE_INVALID_BACKING_PAGE ,
3505
+ };
3506
+
3507
+ static int avic_incomplete_ipi_interception (struct vcpu_svm * svm )
3508
+ {
3509
+ u32 icrh = svm -> vmcb -> control .exit_info_1 >> 32 ;
3510
+ u32 icrl = svm -> vmcb -> control .exit_info_1 ;
3511
+ u32 id = svm -> vmcb -> control .exit_info_2 >> 32 ;
3512
+ u32 index = svm -> vmcb -> control .exit_info_2 && 0xFF ;
3513
+ struct kvm_lapic * apic = svm -> vcpu .arch .apic ;
3514
+
3515
+ trace_kvm_avic_incomplete_ipi (svm -> vcpu .vcpu_id , icrh , icrl , id , index );
3516
+
3517
+ switch (id ) {
3518
+ case AVIC_IPI_FAILURE_INVALID_INT_TYPE :
3519
+ /*
3520
+ * AVIC hardware handles the generation of
3521
+ * IPIs when the specified Message Type is Fixed
3522
+ * (also known as fixed delivery mode) and
3523
+ * the Trigger Mode is edge-triggered. The hardware
3524
+ * also supports self and broadcast delivery modes
3525
+ * specified via the Destination Shorthand(DSH)
3526
+ * field of the ICRL. Logical and physical APIC ID
3527
+ * formats are supported. All other IPI types cause
3528
+ * a #VMEXIT, which needs to emulated.
3529
+ */
3530
+ kvm_lapic_reg_write (apic , APIC_ICR2 , icrh );
3531
+ kvm_lapic_reg_write (apic , APIC_ICR , icrl );
3532
+ break ;
3533
+ case AVIC_IPI_FAILURE_TARGET_NOT_RUNNING : {
3534
+ int i ;
3535
+ struct kvm_vcpu * vcpu ;
3536
+ struct kvm * kvm = svm -> vcpu .kvm ;
3537
+ struct kvm_lapic * apic = svm -> vcpu .arch .apic ;
3538
+
3539
+ /*
3540
+ * At this point, we expect that the AVIC HW has already
3541
+ * set the appropriate IRR bits on the valid target
3542
+ * vcpus. So, we just need to kick the appropriate vcpu.
3543
+ */
3544
+ kvm_for_each_vcpu (i , vcpu , kvm ) {
3545
+ bool m = kvm_apic_match_dest (vcpu , apic ,
3546
+ icrl & KVM_APIC_SHORT_MASK ,
3547
+ GET_APIC_DEST_FIELD (icrh ),
3548
+ icrl & KVM_APIC_DEST_MASK );
3549
+
3550
+ if (m && !avic_vcpu_is_running (vcpu ))
3551
+ kvm_vcpu_wake_up (vcpu );
3552
+ }
3553
+ break ;
3554
+ }
3555
+ case AVIC_IPI_FAILURE_INVALID_TARGET :
3556
+ break ;
3557
+ case AVIC_IPI_FAILURE_INVALID_BACKING_PAGE :
3558
+ WARN_ONCE (1 , "Invalid backing page\n" );
3559
+ break ;
3560
+ default :
3561
+ pr_err ("Unknown IPI interception\n" );
3562
+ }
3563
+
3564
+ return 1 ;
3565
+ }
3566
+
3567
+ static u32 * avic_get_logical_id_entry (struct kvm_vcpu * vcpu , u32 ldr , bool flat )
3568
+ {
3569
+ struct kvm_arch * vm_data = & vcpu -> kvm -> arch ;
3570
+ int index ;
3571
+ u32 * logical_apic_id_table ;
3572
+ int dlid = GET_APIC_LOGICAL_ID (ldr );
3573
+
3574
+ if (!dlid )
3575
+ return NULL ;
3576
+
3577
+ if (flat ) { /* flat */
3578
+ index = ffs (dlid ) - 1 ;
3579
+ if (index > 7 )
3580
+ return NULL ;
3581
+ } else { /* cluster */
3582
+ int cluster = (dlid & 0xf0 ) >> 4 ;
3583
+ int apic = ffs (dlid & 0x0f ) - 1 ;
3584
+
3585
+ if ((apic < 0 ) || (apic > 7 ) ||
3586
+ (cluster >= 0xf ))
3587
+ return NULL ;
3588
+ index = (cluster << 2 ) + apic ;
3589
+ }
3590
+
3591
+ logical_apic_id_table = (u32 * ) page_address (vm_data -> avic_logical_id_table_page );
3592
+
3593
+ return & logical_apic_id_table [index ];
3594
+ }
3595
+
3596
+ static int avic_ldr_write (struct kvm_vcpu * vcpu , u8 g_physical_id , u32 ldr ,
3597
+ bool valid )
3598
+ {
3599
+ bool flat ;
3600
+ u32 * entry , new_entry ;
3601
+
3602
+ flat = kvm_lapic_get_reg (vcpu -> arch .apic , APIC_DFR ) == APIC_DFR_FLAT ;
3603
+ entry = avic_get_logical_id_entry (vcpu , ldr , flat );
3604
+ if (!entry )
3605
+ return - EINVAL ;
3606
+
3607
+ new_entry = READ_ONCE (* entry );
3608
+ new_entry &= ~AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK ;
3609
+ new_entry |= (g_physical_id & AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK );
3610
+ if (valid )
3611
+ new_entry |= AVIC_LOGICAL_ID_ENTRY_VALID_MASK ;
3612
+ else
3613
+ new_entry &= ~AVIC_LOGICAL_ID_ENTRY_VALID_MASK ;
3614
+ WRITE_ONCE (* entry , new_entry );
3615
+
3616
+ return 0 ;
3617
+ }
3618
+
3619
+ static int avic_handle_ldr_update (struct kvm_vcpu * vcpu )
3620
+ {
3621
+ int ret ;
3622
+ struct vcpu_svm * svm = to_svm (vcpu );
3623
+ u32 ldr = kvm_lapic_get_reg (vcpu -> arch .apic , APIC_LDR );
3624
+
3625
+ if (!ldr )
3626
+ return 1 ;
3627
+
3628
+ ret = avic_ldr_write (vcpu , vcpu -> vcpu_id , ldr , true);
3629
+ if (ret && svm -> ldr_reg ) {
3630
+ avic_ldr_write (vcpu , 0 , svm -> ldr_reg , false);
3631
+ svm -> ldr_reg = 0 ;
3632
+ } else {
3633
+ svm -> ldr_reg = ldr ;
3634
+ }
3635
+ return ret ;
3636
+ }
3637
+
3638
+ static int avic_handle_apic_id_update (struct kvm_vcpu * vcpu )
3639
+ {
3640
+ u64 * old , * new ;
3641
+ struct vcpu_svm * svm = to_svm (vcpu );
3642
+ u32 apic_id_reg = kvm_lapic_get_reg (vcpu -> arch .apic , APIC_ID );
3643
+ u32 id = (apic_id_reg >> 24 ) & 0xff ;
3644
+
3645
+ if (vcpu -> vcpu_id == id )
3646
+ return 0 ;
3647
+
3648
+ old = avic_get_physical_id_entry (vcpu , vcpu -> vcpu_id );
3649
+ new = avic_get_physical_id_entry (vcpu , id );
3650
+ if (!new || !old )
3651
+ return 1 ;
3652
+
3653
+ /* We need to move physical_id_entry to new offset */
3654
+ * new = * old ;
3655
+ * old = 0ULL ;
3656
+ to_svm (vcpu )-> avic_physical_id_cache = new ;
3657
+
3658
+ /*
3659
+ * Also update the guest physical APIC ID in the logical
3660
+ * APIC ID table entry if already setup the LDR.
3661
+ */
3662
+ if (svm -> ldr_reg )
3663
+ avic_handle_ldr_update (vcpu );
3664
+
3665
+ return 0 ;
3666
+ }
3667
+
3668
+ static int avic_handle_dfr_update (struct kvm_vcpu * vcpu )
3669
+ {
3670
+ struct vcpu_svm * svm = to_svm (vcpu );
3671
+ struct kvm_arch * vm_data = & vcpu -> kvm -> arch ;
3672
+ u32 dfr = kvm_lapic_get_reg (vcpu -> arch .apic , APIC_DFR );
3673
+ u32 mod = (dfr >> 28 ) & 0xf ;
3674
+
3675
+ /*
3676
+ * We assume that all local APICs are using the same type.
3677
+ * If this changes, we need to flush the AVIC logical
3678
+ * APID id table.
3679
+ */
3680
+ if (vm_data -> ldr_mode == mod )
3681
+ return 0 ;
3682
+
3683
+ clear_page (page_address (vm_data -> avic_logical_id_table_page ));
3684
+ vm_data -> ldr_mode = mod ;
3685
+
3686
+ if (svm -> ldr_reg )
3687
+ avic_handle_ldr_update (vcpu );
3688
+ return 0 ;
3689
+ }
3690
+
3691
+ static int avic_unaccel_trap_write (struct vcpu_svm * svm )
3692
+ {
3693
+ struct kvm_lapic * apic = svm -> vcpu .arch .apic ;
3694
+ u32 offset = svm -> vmcb -> control .exit_info_1 &
3695
+ AVIC_UNACCEL_ACCESS_OFFSET_MASK ;
3696
+
3697
+ switch (offset ) {
3698
+ case APIC_ID :
3699
+ if (avic_handle_apic_id_update (& svm -> vcpu ))
3700
+ return 0 ;
3701
+ break ;
3702
+ case APIC_LDR :
3703
+ if (avic_handle_ldr_update (& svm -> vcpu ))
3704
+ return 0 ;
3705
+ break ;
3706
+ case APIC_DFR :
3707
+ avic_handle_dfr_update (& svm -> vcpu );
3708
+ break ;
3709
+ default :
3710
+ break ;
3711
+ }
3712
+
3713
+ kvm_lapic_reg_write (apic , offset , kvm_lapic_get_reg (apic , offset ));
3714
+
3715
+ return 1 ;
3716
+ }
3717
+
3718
+ static bool is_avic_unaccelerated_access_trap (u32 offset )
3719
+ {
3720
+ bool ret = false;
3721
+
3722
+ switch (offset ) {
3723
+ case APIC_ID :
3724
+ case APIC_EOI :
3725
+ case APIC_RRR :
3726
+ case APIC_LDR :
3727
+ case APIC_DFR :
3728
+ case APIC_SPIV :
3729
+ case APIC_ESR :
3730
+ case APIC_ICR :
3731
+ case APIC_LVTT :
3732
+ case APIC_LVTTHMR :
3733
+ case APIC_LVTPC :
3734
+ case APIC_LVT0 :
3735
+ case APIC_LVT1 :
3736
+ case APIC_LVTERR :
3737
+ case APIC_TMICT :
3738
+ case APIC_TDCR :
3739
+ ret = true;
3740
+ break ;
3741
+ default :
3742
+ break ;
3743
+ }
3744
+ return ret ;
3745
+ }
3746
+
3747
+ static int avic_unaccelerated_access_interception (struct vcpu_svm * svm )
3748
+ {
3749
+ int ret = 0 ;
3750
+ u32 offset = svm -> vmcb -> control .exit_info_1 &
3751
+ AVIC_UNACCEL_ACCESS_OFFSET_MASK ;
3752
+ u32 vector = svm -> vmcb -> control .exit_info_2 &
3753
+ AVIC_UNACCEL_ACCESS_VECTOR_MASK ;
3754
+ bool write = (svm -> vmcb -> control .exit_info_1 >> 32 ) &
3755
+ AVIC_UNACCEL_ACCESS_WRITE_MASK ;
3756
+ bool trap = is_avic_unaccelerated_access_trap (offset );
3757
+
3758
+ trace_kvm_avic_unaccelerated_access (svm -> vcpu .vcpu_id , offset ,
3759
+ trap , write , vector );
3760
+ if (trap ) {
3761
+ /* Handling Trap */
3762
+ WARN_ONCE (!write , "svm: Handling trap read.\n" );
3763
+ ret = avic_unaccel_trap_write (svm );
3764
+ } else {
3765
+ /* Handling Fault */
3766
+ ret = (emulate_instruction (& svm -> vcpu , 0 ) == EMULATE_DONE );
3767
+ }
3768
+
3769
+ return ret ;
3770
+ }
3771
+
3495
3772
static int (* const svm_exit_handlers [])(struct vcpu_svm * svm ) = {
3496
3773
[SVM_EXIT_READ_CR0 ] = cr_interception ,
3497
3774
[SVM_EXIT_READ_CR3 ] = cr_interception ,
@@ -3555,6 +3832,8 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
3555
3832
[SVM_EXIT_XSETBV ] = xsetbv_interception ,
3556
3833
[SVM_EXIT_NPF ] = pf_interception ,
3557
3834
[SVM_EXIT_RSM ] = emulate_on_interception ,
3835
+ [SVM_EXIT_AVIC_INCOMPLETE_IPI ] = avic_incomplete_ipi_interception ,
3836
+ [SVM_EXIT_AVIC_UNACCELERATED_ACCESS ] = avic_unaccelerated_access_interception ,
3558
3837
};
3559
3838
3560
3839
static void dump_vmcb (struct kvm_vcpu * vcpu )
0 commit comments