66#include <linux/kvm_host.h>
77#include <linux/entry-kvm.h>
88#include <asm/fpu.h>
9+ #include <asm/lbt.h>
910#include <asm/loongarch.h>
1011#include <asm/setup.h>
1112#include <asm/time.h>
@@ -983,12 +984,66 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
983984 return 0 ;
984985}
985986
987+ #ifdef CONFIG_CPU_HAS_LBT
988+ int kvm_own_lbt (struct kvm_vcpu * vcpu )
989+ {
990+ if (!kvm_guest_has_lbt (& vcpu -> arch ))
991+ return - EINVAL ;
992+
993+ preempt_disable ();
994+ set_csr_euen (CSR_EUEN_LBTEN );
995+ _restore_lbt (& vcpu -> arch .lbt );
996+ vcpu -> arch .aux_inuse |= KVM_LARCH_LBT ;
997+ preempt_enable ();
998+
999+ return 0 ;
1000+ }
1001+
1002+ static void kvm_lose_lbt (struct kvm_vcpu * vcpu )
1003+ {
1004+ preempt_disable ();
1005+ if (vcpu -> arch .aux_inuse & KVM_LARCH_LBT ) {
1006+ _save_lbt (& vcpu -> arch .lbt );
1007+ clear_csr_euen (CSR_EUEN_LBTEN );
1008+ vcpu -> arch .aux_inuse &= ~KVM_LARCH_LBT ;
1009+ }
1010+ preempt_enable ();
1011+ }
1012+
1013+ static void kvm_check_fcsr (struct kvm_vcpu * vcpu , unsigned long fcsr )
1014+ {
1015+ /*
1016+ * If TM is enabled, top register save/restore will
1017+ * cause lbt exception, here enable lbt in advance
1018+ */
1019+ if (fcsr & FPU_CSR_TM )
1020+ kvm_own_lbt (vcpu );
1021+ }
1022+
1023+ static void kvm_check_fcsr_alive (struct kvm_vcpu * vcpu )
1024+ {
1025+ if (vcpu -> arch .aux_inuse & KVM_LARCH_FPU ) {
1026+ if (vcpu -> arch .aux_inuse & KVM_LARCH_LBT )
1027+ return ;
1028+ kvm_check_fcsr (vcpu , read_fcsr (LOONGARCH_FCSR0 ));
1029+ }
1030+ }
1031+ #else
1032+ static inline void kvm_lose_lbt (struct kvm_vcpu * vcpu ) { }
1033+ static inline void kvm_check_fcsr (struct kvm_vcpu * vcpu , unsigned long fcsr ) { }
1034+ static inline void kvm_check_fcsr_alive (struct kvm_vcpu * vcpu ) { }
1035+ #endif
1036+
9861037/* Enable FPU and restore context */
9871038void kvm_own_fpu (struct kvm_vcpu * vcpu )
9881039{
9891040 preempt_disable ();
9901041
991- /* Enable FPU */
1042+ /*
1043+ * Enable FPU for guest
1044+ * Set FR and FRE according to guest context
1045+ */
1046+ kvm_check_fcsr (vcpu , vcpu -> arch .fpu .fcsr );
9921047 set_csr_euen (CSR_EUEN_FPEN );
9931048
9941049 kvm_restore_fpu (& vcpu -> arch .fpu );
@@ -1008,6 +1063,7 @@ int kvm_own_lsx(struct kvm_vcpu *vcpu)
10081063 preempt_disable ();
10091064
10101065 /* Enable LSX for guest */
1066+ kvm_check_fcsr (vcpu , vcpu -> arch .fpu .fcsr );
10111067 set_csr_euen (CSR_EUEN_LSXEN | CSR_EUEN_FPEN );
10121068 switch (vcpu -> arch .aux_inuse & KVM_LARCH_FPU ) {
10131069 case KVM_LARCH_FPU :
@@ -1042,6 +1098,7 @@ int kvm_own_lasx(struct kvm_vcpu *vcpu)
10421098
10431099 preempt_disable ();
10441100
1101+ kvm_check_fcsr (vcpu , vcpu -> arch .fpu .fcsr );
10451102 set_csr_euen (CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN );
10461103 switch (vcpu -> arch .aux_inuse & (KVM_LARCH_FPU | KVM_LARCH_LSX )) {
10471104 case KVM_LARCH_LSX :
@@ -1073,6 +1130,7 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu)
10731130{
10741131 preempt_disable ();
10751132
1133+ kvm_check_fcsr_alive (vcpu );
10761134 if (vcpu -> arch .aux_inuse & KVM_LARCH_LASX ) {
10771135 kvm_save_lasx (& vcpu -> arch .fpu );
10781136 vcpu -> arch .aux_inuse &= ~(KVM_LARCH_LSX | KVM_LARCH_FPU | KVM_LARCH_LASX );
@@ -1095,6 +1153,7 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu)
10951153 /* Disable FPU */
10961154 clear_csr_euen (CSR_EUEN_FPEN );
10971155 }
1156+ kvm_lose_lbt (vcpu );
10981157
10991158 preempt_enable ();
11001159}
0 commit comments