KVM: arm/arm64: Prepare to handle deferred save/restore of SPSR_EL1
authorChristoffer Dall <christoffer.dall@linaro.org>
Wed, 27 Dec 2017 19:01:52 +0000 (20:01 +0100)
committerMarc Zyngier <marc.zyngier@arm.com>
Mon, 19 Mar 2018 10:53:17 +0000 (10:53 +0000)
SPSR_EL1 is not used by a VHE host kernel and can be deferred, but we
need to rework the accesses to this register to access the latest value
depending on whether or not guest system registers are loaded on the CPU
or only reside in memory.

The handling of accessing the various banked SPSRs for 32-bit VMs is a
bit clunky, but this will be improved in following patches which will
first prepare and subsequently implement deferred save/restore of the
32-bit registers, including the 32-bit SPSRs.

Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
arch/arm/include/asm/kvm_emulate.h
arch/arm/kvm/emulate.c
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/kvm/inject_fault.c
virt/kvm/arm/aarch32.c

index e27caa4b47a1bff6e9644a82e7ad2e2b3a6acb1c..6493bd479ddc9e756362020f8cf49a4c968a17fb 100644 (file)
@@ -41,7 +41,17 @@ static inline unsigned long *vcpu_reg32(struct kvm_vcpu *vcpu, u8 reg_num)
        return vcpu_reg(vcpu, reg_num);
 }
 
-unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu);
+unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu);
+
+static inline unsigned long vpcu_read_spsr(struct kvm_vcpu *vcpu)
+{
+       return *__vcpu_spsr(vcpu);
+}
+
+static inline void vcpu_write_spsr(struct kvm_vcpu *vcpu, unsigned long v)
+{
+       *__vcpu_spsr(vcpu) = v;
+}
 
 static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
                                         u8 reg_num)
index fa501bf437f3bb9301b1024e65112d85114cb993..9046b53d87c198bb61890a8aefe08bf7a7b0660b 100644 (file)
@@ -142,7 +142,7 @@ unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num)
 /*
  * Return the SPSR for the current mode of the virtual CPU.
  */
-unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu)
+unsigned long *__vcpu_spsr(struct kvm_vcpu *vcpu)
 {
        unsigned long mode = *vcpu_cpsr(vcpu) & MODE_MASK;
        switch (mode) {
index d313aaae5c380ad8c0c3954df3ec2fd089511ce2..f32640132e26f697b9720b12a03fbac9699c7626 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <asm/esr.h>
 #include <asm/kvm_arm.h>
+#include <asm/kvm_hyp.h>
 #include <asm/kvm_mmio.h>
 #include <asm/ptrace.h>
 #include <asm/cputype.h>
@@ -143,13 +144,43 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
                vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
 }
 
-/* Get vcpu SPSR for current mode */
-static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
+static inline unsigned long vcpu_read_spsr(const struct kvm_vcpu *vcpu)
 {
-       if (vcpu_mode_is_32bit(vcpu))
-               return vcpu_spsr32(vcpu);
+       unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
+
+       if (vcpu_mode_is_32bit(vcpu)) {
+               unsigned long *p_32bit = vcpu_spsr32(vcpu);
+
+               /* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
+               if (p_32bit != p)
+                       return *p_32bit;
+       }
+
+       if (vcpu->arch.sysregs_loaded_on_cpu)
+               return read_sysreg_el1(spsr);
+       else
+               return *p;
+}
 
-       return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
+static inline void vcpu_write_spsr(const struct kvm_vcpu *vcpu, unsigned long v)
+{
+       unsigned long *p = (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
+
+       /* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
+       if (vcpu_mode_is_32bit(vcpu)) {
+               unsigned long *p_32bit = vcpu_spsr32(vcpu);
+
+               /* KVM_SPSR_SVC aliases KVM_SPSR_EL1 */
+               if (p_32bit != p) {
+                       *p_32bit = v;
+                       return;
+               }
+       }
+
+       if (vcpu->arch.sysregs_loaded_on_cpu)
+               write_sysreg_el1(v, spsr);
+       else
+               *p = v;
 }
 
 static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
index 63dba401fc7d234b26977b6c1972f034c2e3c2ae..7f8d2a4e420f71affbaa981935848b782781ded7 100644 (file)
@@ -71,7 +71,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr
        *vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
 
        *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
-       *vcpu_spsr(vcpu) = cpsr;
+       vcpu_write_spsr(vcpu, cpsr);
 
        vcpu_write_sys_reg(vcpu, addr, FAR_EL1);
 
@@ -106,7 +106,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu)
        *vcpu_pc(vcpu) = get_except_vector(vcpu, except_type_sync);
 
        *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
-       *vcpu_spsr(vcpu) = cpsr;
+       vcpu_write_spsr(vcpu, cpsr);
 
        /*
         * Build an unknown exception, depending on the instruction
index 8bc479fa37e6565305546709f433a1a2a49c302b..efc84cbe8277944fdea216e07d79cd23eb432f6c 100644 (file)
@@ -178,7 +178,7 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
        *vcpu_cpsr(vcpu) = cpsr;
 
        /* Note: These now point to the banked copies */
-       *vcpu_spsr(vcpu) = new_spsr_value;
+       vcpu_write_spsr(vcpu, new_spsr_value);
        *vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
 
        /* Branch to exception vector */